packages feed

hvega (empty) → 0.1.0.0

raw patch · 6 files changed

+4628/−0 lines, 6 filesdep +aesondep +basedep +textsetup-changedbinary-added

Dependencies added: aeson, base, text, vector

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2018++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 Author name here 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.
+ README.md view
@@ -0,0 +1,57 @@+# hvega++Support the creation of [Vega-Lite](https://vega.github.io/vega-lite/) visualizations+in Haskell. This code is released under the BSD3 license.++It is an almost-direct copy of version 2.2.1 of the+[Elm Vega library](http://package.elm-lang.org/packages/gicentre/elm-vega/2.2.1/VegaLite),+which is released under a BSD3 license by Jo Wood of the giCentre at the+City University of London.++## Example++```Haskell+let cars =  dataFromUrl "https://vega.github.io/vega-datasets/data/cars.json" []++    enc = encoding+            . position X [ PName "Horsepower", PmType Quantitative ]+            . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]+            . color [ MName "Origin", MmType Nominal ]++    bkg = background "rgba(0, 0, 0, 0.05)"++in toVegaLite [ bkg, cars, mark Circle [], enc [] ]+```++When viewed with a Vega-Lite aware viewer, the resultant plot is++![Simple scatterplot](https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/images/intro.png "Simple scatterplot")++## Documentation++The [Elm Vega documentation](http://package.elm-lang.org/packages/gicentre/elm-vega/2.2.1)+can be used as a guide to using this module. The+[Vega-Lite Example Gallery](https://vega.github.io/vega-lite/examples/) has+been converted to an+[IHaskell notebook](https://github.com/DougBurke/hvega/blob/master/notebooks/VegaLiteGallery.ipynb)+(unfortunately the plots created by VegaEmbed **do not appear**+in the notebook when viewed with either GitHub's viewer or+[ipynb viewer](http://nbviewer.jupyter.org/github/DougBurke/hvega/blob/master/notebooks/VegaLiteGallery.ipynb)).++## Differences to Elm Vega++The main changes to version 2.2.1 of+[Elm Vega](http://package.elm-lang.org/packages/gicentre/elm-vega/2.2.1)+are:++- Replace `Spec` by `VLSpec` (although both are synonyms for the underlying+  JSON representation).++- Add a type for the output of `toVegaLite` (`VegaLite`) that is separate from+  `VLSpec`, which is usefull for integration with IHaskell. The JSON+  specification is retrieved with `fromVL`.++- Take advantage of the lack of backwards compatibality requirements to remove or+  replace several symbols (such as add the `Utc` constructor to `TimeUnit`, remove the `bin`+  function, and use `Data` rather than `(VLProperty, VLSpec)` in function+  signatures).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hvega.cabal view
@@ -0,0 +1,32 @@+name:                hvega+version:             0.1.0.0+synopsis:            Create Vega and Vega-Lite visualizations.+description:         This is an almost-direct port of elm-vega+                     (<http://package.elm-lang.org/packages/gicentre/elm-vega/2.2.1>)+                     to Haskell.+homepage:            https://github.com/DougBurke/hvega+license:             BSD3+license-file:        LICENSE+author:              Douglas Burke+maintainer:          dburke.gw@gmail.com+copyright:           2018 Douglas Burke+category:            Graphics+build-type:          Simple+extra-source-files:  README.md+extra-doc-files:     images/example.png+cabal-version:       >=1.18++library+  hs-source-dirs:      src+  exposed-modules:     Graphics.Vega.VegaLite+  build-depends:       base >= 4.7 && < 5+                     , aeson >= 0.11 && < 1.3+                     , text == 1.2.*+                     , vector >= 0.11 && < 0.13+                     +  default-language:    Haskell2010+  ghc-options:         -Wall++source-repository head+  type:     git+  location: https://github.com/DougBurke/hvega
+ images/example.png view

binary file changed (absent → 6122 bytes)

+ src/Graphics/Vega/VegaLite.hs view
@@ -0,0 +1,4507 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}++{-|+Module      : Graphics.Vega.VegaLite+Copyright   : (c) Douglas Burke, 2018+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : Requires OverloadedStrings, TupleSections++This is essentially a straight port of the +<http://package.elm-lang.org/packages/gicentre/elm-vega/2.2.1/VegaLite Elm Vega Lite module>+(version 2.2.1).+It allows users to create a Vega-Lite specification, targeting+version 2 of the <https://vega.github.io/schema/vega-lite/v2.json JSON schema>.+The ihaskell-hvega module provides an easy way to embed Vega-Lite+visualizations in an IHaskell notebook (using+<https://vega.github.io/vega-lite/usage/embed.html Vega-Embed>).++The major change to version 2.2.1 of the Elm version is that the type representing+the full Vega-Lite specification - that is, the return value of+'toVegaLite' - is not a 'VLSpec' (an alias for 'Data.Aeson.Value')+but is instead a newtype around this ('VegaLite'). There are also some minor+changes to the exported types and symbols (e.g. 'Utc' is exported rather than+@utc@ and @bin@ is not exported). ++Note that this module exports several symbols that are exported+by the Prelude, namely 'Left', 'Right', 'filter', 'lookup',+and 'repeat'.++== Example++@+let desc = "A very exciting bar chart"++    dat = dataFromRows [Parse [("start", FoDate "%Y-%m-%d")]]+          . dataRow [("start", Str "2011-03-25"), ("count", Number 23)]+          . dataRow [("start", Str "2011-04-02"), ("count", Number 45)]+          . dataRow [("start", Str "2011-04-12"), ("count", Number 3)]++    barOpts = [MOpacity 0.4, MColor "teal"]++    enc = encoding+          . position X [PName "start", PmType Temporal, PAxis [AxTitle "Inception date"]]+          . position Y [PName "count", PmType Quantitative]++    in toVegaLite [description desc, background "white", dat [], mark Bar barOpts, enc []]+@++<<images/example.png>>++-}++module Graphics.Vega.VegaLite+       (+         -- * Creating a Vega-Lite Specification++         toVegaLite+       , fromVL+       , VLProperty+       , VLSpec+       , VegaLite +       , LabelledSpec+       , BuildLabelledSpecs+       , combineSpecs++         -- * Creating the Data Specification+         --+         -- Functions and types for declaring the input data to the+         -- visualization.+         +       , dataFromUrl+       , dataFromColumns+       , dataFromRows+       , dataFromJson+       , dataFromSource+       , datasets+       , dataColumn+       , dataRow+       , geometry+       , geoFeatureCollection+       , geometryCollection+       , Data+       , DataColumn+       , DataRow+       , Format(..)+       , Geometry(..)+       , DataType(..)++         -- * Creating the Transform Specification+         --+         -- Functions and types for declaring the transformation rules that+         -- are applied to data fields or geospatial coordinates before they+         -- are encoded visually.+         +       , transform+       , projection+       , ProjectionProperty(..)+       , Projection(..)+       , ClipRect(..)+         +         -- ** Aggregation+         +       , aggregate+       , Operation(..)+       , opAs+       , timeUnitAs++         -- ** Binning++       , binAs+       , BinProperty(..)+         +         -- ** Data Calculation++       , calculateAs++         -- ** Filtering++       , filter+       , Filter(..)+       , FilterRange(..)++         -- ** Relational Joining (lookup)++       , lookup+       , lookupAs++         -- * Creating the Mark Specification+         --+         -- Types and functions for declaring the type of visual+         -- marks used in the visualization.++       , mark+       , Mark(..)+       , MarkProperty(..)+       , MarkOrientation(..)+       , MarkInterpolation(..)+       , Symbol(..)+       , Cursor(..)++         -- * Creating the Encoding Specification+         --+         -- $encoding+         +       , encoding+       , Measurement(..)++         -- ** Position Channels+         --+         -- Control where items appear in the visualization.++       , position+       , PositionChannel(..)+       , Position(..)+       , SortProperty(..)+       , StackProperty(..)+       , AxisProperty(..)+       , OverlapStrategy(..)+       , Side(..)+       , HAlign(..)+       , VAlign(..)+       , FontWeight(..)+       , TimeUnit(..)+         +         -- ** Mark channels+         --+         -- Control the appearance of the visual marks in the visualization+         -- (e.g. 'color' and 'size').++       , size+       , color+       , fill+       , stroke+       , opacity+       , shape+       , MarkChannel(..)+       , LegendProperty(..)+       , Legend(..)+       , LegendOrientation(..)+       , LegendValues(..)++         -- ** Text Channels+         --+         -- Control the appearance of the text and tooltip elements in the visualization.++       , text+       , tooltip+       , TextChannel(..)+         +         -- ** Hyperlink Channels+         --+         -- $hyperlink+         +       , hyperlink+       , HyperlinkChannel(..)++         -- ** Order Channels+         --+         -- $order++       , order+       , OrderChannel(..)++         -- ** Facet Channels+         --+         -- $facet++       , row+       , column+         +         -- ** Level of detail Channel+         --+         -- $detail+         +       , detail+       , DetailChannel(..)++         -- ** Scaling+         --+         -- How the encoding of a data field is applied.++       , ScaleProperty(..)+       , Scale(..)+       , categoricalDomainMap+       , domainRangeMap+       , ScaleDomain(..)+       , ScaleRange(..)+       , ScaleNice(..)+       , CInterpolate(..)+         +         -- * Creating view compositions+         --+         -- $view++       , layer+       , hConcat+       , vConcat+       , resolve+       , resolution+       , Resolve(..)+       , Channel(..)+       , Resolution(..)++         -- ** Faceted views+         -- #facetview#+         --+         -- $facetview++       , repeat+       , RepeatFields(..)+       , facet+       , FacetMapping(..)+       , FacetChannel(..)+       , asSpec+       , specification+       , Arrangement(..)+       , HeaderProperty(..)++         -- * Creating Selections for Interaction+         --+         -- $selections++       , selection+       , select+       , Selection(..)+       , SelectionProperty(..)+       , Binding(..)+       , InputProperty(..)+       , SelectionResolution(..)+       , SelectionMarkProperty(..)++         -- ** Making conditional channel encodings+         --+         -- $conditional++       , BooleanOp(..)++         -- * Global Configuration+         --+         -- Configuration options that affect the entire visualization. These are in addition+         -- to the data and transform options described above.++       , name+       , title+       , description+       , height+       , width+       , padding+       , autosize+       , background+       , configure+       , configuration+       , ConfigurationProperty(..)+       , Autosize(..)+       , Padding(..)+       , AxisConfig(..)+       , LegendConfig(..)+       , ScaleConfig(..)+       , TitleConfig(..)+       , APosition(..)+       , ViewConfig(..)+       , RangeConfig(..)+       , FieldTitleProperty(..)+         +         -- * General Data types+         --+         -- In addition to more general data types like integers and string, the following types+         -- can carry data used in specifications.++       , DataValue(..)+       , DataValues(..)+       , DateTime(..)+       , MonthName(..)+       , DayName(..)++        )+    where++-- VegaLite uses these symbols.+import Prelude hiding (Either(..), filter, lookup, repeat)++import qualified Data.Aeson as A+import qualified Data.Text as T+import qualified Data.Vector as V++import Control.Arrow (first, second)++-- Aeson's Value type conflicts with the Number type+import Data.Aeson ((.=), Value, decode, encode, object, toJSON)+import Data.Maybe (fromMaybe, mapMaybe)+import Data.Monoid ((<>))++-- Documentation++-- $encoding+-- Types and functions for declaring which data fields are mapped to which+-- channels. Channels can include: position on screen (e.g. 'X', 'Y'); visual+-- mark properties ('color', 'size', 'stroke', 'shape'); 'text'; 'hyperlink';+-- ordering ('order'); level of 'detail'; and facets for composed+-- visualizations ('facet'). All can be further customised via a series of+-- properties that determine how the encoding is implemented (such as+-- scaling, sorting, and spacing).++-- $hyperlink+-- Channels which offer a clickable URL destination. Unlike most other+-- channels, the hyperlink channel has no direct visual expression other than the+-- option of changing the cursor style when hovering, so an encoding will usually+-- pair hyperlinks with other visual channels such as marks or texts.++-- $order+-- Channels that relate to the order of data fields such as for sorting stacking order+-- or order of data points in a connected scatterplot. See the+-- <https://vega.github.io/vega-lite/docs/encoding.html#order Vega-Lite documentation>+-- for further details.++-- $facet+-- Channels for faceting single plots into small multiples. Can be used to create+-- trellis plots or other arrangements in rows and columns. See the+-- <https://vega.github.io/vega-lite/docs/encoding.html#facet Vega-Lite documentation>+-- for further details. See also, <#facetview faceted views> for a more flexible (but+-- more verbose) way of defining faceted views.++-- NOTE: the facetview link above doesn't seem to work. Argh.++-- $detail+-- Used for grouping data but without changing the visual appearance of a mark. When,+-- for example, a field is encoded by color, all data items with the same value for+-- that field are given the same color. When a detail channel encodes a field, all+-- data items with the same value are placed in the same group. This allows, for example+-- a line chart with multiple lines to be created – one for each group. See the+-- <https://vega.github.io/vega-lite/docs/encoding.html#detail Vega-Lite documentation>+-- for more information.++-- $view+-- Views can be combined to create more complex multiview displays. This may involve+-- layering views on top of each other (superposition) or laying them out in adjacent+-- spaces (juxtaposition using 'repeat', 'facet', 'hConcat', or 'vConcat'). Where different+-- views have potentially conflicting channels (for example, two position scales in+-- a layered visualization) the rules for resolving them can be defined with 'resolve'.+-- For details of creating composite views see the+-- <https://vega.github.io/vega-lite/docs/composition.html Vega-Lite documentation>.++-- $facetview+-- These are small multiples each of which show subsets of the same dataset. The specification+-- determines which field should be used to determine subsets along with their spatial+-- arrangement (in rows or columns). For details see the+-- <https://vega.github.io/vega-lite/docs/facet.html Vega-Lite documentation>.++-- $selections+-- Selections are the way in which interactions (such as clicking or dragging) can be+-- responded to in a visualization. They transform interactions into data queries.+-- For details, see the+-- <https://vega.github.io/vega-lite/docs/selection.html Vega-Lite documentation>.++-- $conditional+-- Sometimes it is useful to make channel encoding conditional on something. For example,+-- on the result of some interaction such as clicking or dragging or some data property+-- such whether null or an outlier. 'MSelectionCondition' and 'TSelectionCondition' will+-- encode a mark or text dependent on an interactive selection. 'MDataCondition'+-- and 'TDataCondition' will encode it dependening on some data property.+--+-- For interaction, once a selection has been defined and named, supplying a set of+-- 'MSelectionCondition' encodings allow mark encodings to become dependent on that selection.+-- 'MSelectionCondition' is followed firstly by a Boolean expression relating to the+-- selection upon which it is dependent, then an \"if\" and an \"else\" clause. Each clause+-- is a list of mark field encodings that should be applied when the selection is true+-- (the \"if clause\") and when it is false (the \"else clause\"). The color encoding below+-- is saying \"whenever data marks are selected with an interval mouse drag, encode+-- the cylinder field with an ordinal color scheme, else make them grey\".+--+-- @+-- sel = selection . select "myBrush" Interval []+--+-- enc = encoding+--         . position X [ PName \"Horsepower\", PmType Quantitative ]+--         . position Y [ PName \"Miles_per_Gallon\", PmType Quantitative ]+--         . color+--             [ MSelectionCondition (SelectionName "myBrush")+--                 [ MName \"Cylinders\", MmType Ordinal ]+--                 [ MString "grey" ]+--             ]+-- @+--+-- In a similar way, 'MDataCondition' will encocode a mark in one of two ways depending+-- on whether a predicate test is satisfied.+--+-- @+-- enc = encoding+--         . position X [ PName \"IMDB_Rating\", PmType Quantitative ]+--         . position Y [ PName \"Rotten_Tomatoes_Rating\", PmType Quantitative ]+--           . color+--               [ MDataCondition+--                   (Or (Expr "datum.IMDB_Rating === null")+--                       (Expr "datum.Rotten_Tomatoes_Rating === null")+--                   )+--                   [ MString "#ddd" ]+--                   [ MString "#0099ee" ]+--               ]+-- @+--+-- For details, see the+-- <https://vega.github.io/vega-lite/docs/condition.html Vega-Lite documentation>.+++--- helpers not in VegaLite.elm++aggregate_ :: Operation -> LabelledSpec+aggregate_ op = "aggregate" .= operationLabel op++field_ :: T.Text -> LabelledSpec+field_ f = "field" .= f++op_ :: Operation -> LabelledSpec+op_ op = "op" .= operationLabel op++repeat_ :: Arrangement -> LabelledSpec+repeat_ arr = "repeat" .= arrangementLabel arr++sort_ :: [SortProperty] -> LabelledSpec+sort_ ops = "sort" .= sortPropertySpec ops++timeUnit_ :: TimeUnit -> LabelledSpec+timeUnit_ tu = "timeUnit" .= timeUnitLabel tu++type_ :: Measurement -> LabelledSpec+type_ m = "type" .= measurementLabel m++value_ :: T.Text -> LabelledSpec+value_ v = "value" .= v++fromT :: T.Text -> VLSpec+fromT = toJSON++fromF :: Double -> VLSpec+fromF = toJSON++---------+++-- | A Vega Lite visualization, created by+--   'toVegaLite'. The contents can be extracted with 'fromVL'.+--+newtype VegaLite =+  VL {+  fromVL :: VLSpec+  -- ^ Extract the specification for passing to a VegaLite visualizer.+  --+  --   > let vlSpec = fromVL vl+  --   > Data.ByteString.Lazy.Char8.putStrLn (Data.Aeson.Encode.Pretty.encodePretty vlSpec)+  --+  -- Note that there is __no__ validation done to ensure that the output matches+  -- the Vega Lite schema. That is, it is possible to create an invalid visualization+  -- with this module (e.g. missing a data source or referring to an undefined+  -- field).+  }++-- | The specification is represented as JSON.+type VLSpec = Value++vlSchemaName :: T.Text+vlSchemaName = "https://vega.github.io/schema/vega-lite/v2.json"++{-|++Convert a list of Vega-Lite specifications into a single JSON object that may be+passed to Vega-Lite for graphics generation. Commonly these will include at least+a data, mark, and encoding specification.++While simple properties like 'mark' may be provided directly, it is usually clearer+to label more complex ones such as encodings as separate expressions. This becomes+increasingly helpful for visualizations that involve composition of layers, repeats+and facets.++Specifications can be built up by chaining a series of functions (such as 'dataColumn'+or 'position' in the example below). Functional composition using the '.' operator+allows this to be done compactly.++@+let dat = dataFromColumns []+          . dataColumn "a" (Strings [ \"C", \"C", \"D", \"D", \"E", \"E" ])+          . dataColumn "b" (Numbers [ 2, 7, 1, 2, 6, 8 ])++    enc = encoding+          . position X [ PName "a", PmType Nominal ]+          . position Y [ PName "b", PmType Quantitative, PAggregate Mean ]++in toVegaLite [ dat [], mark Bar [], enc [] ]+@+-}+toVegaLite :: [(VLProperty, VLSpec)] -> VegaLite+toVegaLite vals =+  let kvals = ("$schema" .= vlSchemaName)+              : map toProp vals+      toProp = first vlPropertyLabel+      +  in VL { fromVL = object kvals }+++{-|++Combines a list of labelled specifications into a single specification.+This is useful when you wish to create+a single page with multiple visulizualizations.++@+combineSpecs+    [ ( "vis1", myFirstVis )+    , ( "vis2", mySecondVis )+    , ( "vis3", myOtherVis )+    ]+@+-}+combineSpecs :: [LabelledSpec] -> VLSpec+combineSpecs = object++{-|++Create a specification sufficient to define an element in a composed visualization+such as a superposed layer or juxtaposed facet. Typically a layer will contain a+full set of specifications that define a visualization with+the exception of the data specification which is usually defined outside of any one+layer. Whereas for repeated and faceted specs, the entire specification is provided.++@+spec1 = asSpec [ enc1 [], mark Line [] ]+@+-}+asSpec :: [(VLProperty, VLSpec)] -> VLSpec+asSpec = object . map (first vlPropertyLabel)+++{-|++Specifies a list of geo features to be used in a geoShape specification.+Each feature object in this collection can be created with the 'geometry'+function.++@+geojson =+    geoFeatureCollection+        [ geometry (GeoPolygon [ [ ( -3, 59 ), ( -3, 52 ), ( 4, 52 ), ( -3, 59 ) ] ])+            [ ( "myRegionName", Str "Northern region" ) ]+        , geometry (GeoPolygon [ [ ( -3, 52 ), ( 4, 52 ), ( 4, 45 ), ( -3, 52 ) ] ])+            [ ( "myRegionName", Str "Southern region" ) ]+        ]+@+-}+geoFeatureCollection :: [VLSpec] -> VLSpec+geoFeatureCollection geoms =+  object [ "type" .= ("FeatureCollection" :: T.Text)+         , "features" .=  geoms+         ]+++{-|++Specifies a list of geometry objects to be used in a geoShape specification.+Each geometry object in this collection can be created with the 'geometry'+function.++@+geojson =+    geometryCollection+        [ geometry (GeoPolygon [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []+        , geometry (GeoPoint -3.5 55.5) []+        ]+@+-}+geometryCollection :: [VLSpec] -> VLSpec+geometryCollection geoms =+  object [ "type" .= ("GeometryCollection" :: T.Text)+         , "geometries" .= geoms+         ]+++{-|++Create a named aggregation operation on a field that can be added to a transformation.+For further details see the+<https://vega.github.io/vega-lite/docs/aggregate.html#aggregate-op-def Vega-Lite documentation>.++@+trans =+    transform+        . aggregate+            [ opAs Min "people" "lowerBound"+            , opAs Max "people" "upperBound"+            ]+            [ "age" ]+@+-}+opAs ::+  Operation+  -- ^ The aggregation operation to use.+  -> T.Text+  -- ^ The name of the field which is to be aggregated.+  -> T.Text+  -- ^ The name given to the transformed data.+  -> VLSpec+opAs op field label =+  object [ op_ op+         , field_ field+         , "as" .= label+         ]+++{-|++Top-level Vega-Lite properties. These are the ones that define the core of the+visualization grammar. All properties are created by functions which can be+arranged into seven broad groups:++[Data Properties] These relate to the input data to be visualized. Generated by+'dataFromColumns', 'dataFromRows', 'dataFromUrl', 'dataFromSource' and+'dataFromJson'.++[Transform Properties] These indicate that some transformation of input data should+be applied before encoding them visually. Generated by 'transform'+and 'projection' they can include data transformations such as 'filter',+'binAs' and 'calculateAs' and geo transformations of longitude, latitude coordinates+used by marks such as 'Geoshape', 'Point', and 'Line'.++[Mark Properties] These relate to the symbols used to visualize data items. They+are generated by 'mark', and include types such as 'Circle', 'Bar', and 'Line'.++[Encoding Properties] These specify which data elements are mapped to which mark characteristics+(known as /channels/). Generated by 'encoding', they include encodings+such as 'position', 'color', 'size', 'shape', 'text' and 'hyperlink'.++[Composition Properties] These allow visualization views to be combined to form more+complex visualizations. Generated by 'layer', 'repeat', 'facet',+'hConcat', 'vConcat', 'spec', and 'resolve'.++[Interaction Properties] These allow interactions such as clicking, dragging and others+generated via a GUI or data stream to influence the visualization. Generated by+'selection'.++[Supplementary and Configuration Properties] These provide a means to add metadata and+styling to one or more visualizations. Generated by 'name', 'title', 'description',+'background', 'height', 'width', 'padding', 'autosize', and 'configure'.+-}+data VLProperty+    = VLName+    | VLDescription+    | VLTitle+    | VLWidth+    | VLHeight+    | VLAutosize+    | VLPadding+    | VLBackground+    | VLData+    | VLDatasets+    | VLMark+    | VLTransform+    | VLProjection+    | VLEncoding+    | VLLayer+    | VLHConcat+    | VLVConcat+    | VLRepeat+    | VLFacet+    | VLSpec+    | VLResolve+    | VLConfig+    | VLSelection+++vlPropertyLabel :: VLProperty -> T.Text+vlPropertyLabel VLName = "name"+vlPropertyLabel VLDescription = "description"+vlPropertyLabel VLTitle = "title"+vlPropertyLabel VLWidth = "width"+vlPropertyLabel VLHeight = "height"+vlPropertyLabel VLPadding = "padding"+vlPropertyLabel VLAutosize = "autosize"+vlPropertyLabel VLBackground = "background"+vlPropertyLabel VLData = "data"+vlPropertyLabel VLDatasets = "datasets"+vlPropertyLabel VLProjection = "projection"+vlPropertyLabel VLMark = "mark"+vlPropertyLabel VLTransform = "transform"+vlPropertyLabel VLEncoding = "encoding"+vlPropertyLabel VLConfig = "config"+vlPropertyLabel VLSelection = "selection"+vlPropertyLabel VLHConcat = "hconcat"+vlPropertyLabel VLVConcat = "vconcat"+vlPropertyLabel VLLayer = "layer"+vlPropertyLabel VLRepeat = "repeat"+vlPropertyLabel VLFacet = "facet"+vlPropertyLabel VLSpec = "spec"+vlPropertyLabel VLResolve = "resolve"+++{-|++Indicates the type of data to be parsed when reading input data. For @FoDate@+and @FoUtc@, the formatting specification can be specified using+<https://vega.github.io/vega-lite/docs/data.html#format D3's formatting specifiers>+or left as an empty string if default date formatting is to be applied. Care should+be taken when assuming default parsing of dates because different browsers can+parse dates differently. Being explicit about the date format is usually safer.+-}+data DataType+    = FoNumber+    | FoBoolean+    | FoDate T.Text+    | FoUtc T.Text+++{-|++Specifies the type of format a data source uses. If the format is indicated by+the file name extension (@".tsv"@, @".csv"@, @".json"@) there is no need to indicate the+format explicitly. However this can be useful if the filename extension does not+indicate type (e.g. @".txt"@) or you wish to customise the parsing of a file. For+example, when specifying the @JSON@ format, its parameter indicates the name of+property field containing the attribute data to extract. For details see the+<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>.+-}+data Format+    = JSON T.Text+    | CSV+    | TSV+    | TopojsonFeature T.Text+    | TopojsonMesh T.Text+    | Parse [(T.Text, DataType)]+++{-|++Represents a named Vega-Lite specification, usually generated by a+function in this module. You shouldn't need to create @LabelledSpec@+tuples directly, but they can be useful for type annotations.+-}+type LabelledSpec = (T.Text, VLSpec)++{-|++Represent those functions which can be chained together using function+composition to append new specifications onto an existing list.+-}+type BuildLabelledSpecs = [LabelledSpec] -> [LabelledSpec]++{-|++Represents a single column of data. Used when generating inline data with+'dataColumn'.+-}+type DataColumn = [LabelledSpec]++{-|++Represents a single row of data. Used when generating inline data with+'dataRow'.+-}+type DataRow = VLSpec++{-|++Convenience type annotation label for use with data generation functions.++@+myRegion : [DataColumn] -> Data+myRegion =+    dataFromColumns []+        . dataColumn "easting" (Numbers [ -3, 4, 4, -3, -3 ])+        . dataColumn "northing" (Numbers [ 52, 52, 45, 45, 52 ])+@+-}+type Data = (VLProperty, VLSpec)+++formatProperty :: Format -> [LabelledSpec]+formatProperty (JSON js) =+  let ps = [("type", "json")]+           <> if T.null (T.strip js) then [] else [("property", js)]+  in map (second toJSON) ps+     +formatProperty CSV = [("type", "csv")]+formatProperty TSV = [("type", "tsv")]+formatProperty (TopojsonFeature os) = [ ("type", "topojson")+                                      , ("feature", toJSON os) ]+formatProperty (TopojsonMesh os) = [ ("type", "topojson")+                                   , ("mesh", toJSON os) ]+formatProperty (Parse fmts) =+  let pObj = object (map (second dataTypeSpec) fmts)+  in [("parse", pObj)]+++dataTypeSpec :: DataType -> VLSpec+dataTypeSpec dType =+  let s = case dType of+        FoNumber -> "number"+        FoBoolean -> "boolean"+        FoDate fmt | T.null fmt -> "date"+                   | otherwise -> "date:'" <> fmt <> "'"+        FoUtc fmt | T.null fmt -> "utc"+                  | otherwise -> "utc:'" <> fmt <> "'"+  in toJSON s                   +++{-|++Create a row of data. A row comprises a list of (columnName, value) pairs.+The final parameter is the list of any other rows to which this is added.++@+dataRow [(\"Animal\", Str \"Fish\"), (\"Age\",Number 28), (\"Year\", Str "2010")] []+@+-}+dataRow :: [(T.Text, DataValue)] -> [DataRow] -> [DataRow]+dataRow rw = (object (map (second dataValueSpec) rw) :)+++{-|++Create a dataset comprising a collection of named 'Data' items. Each data item+can be created with normal data generating functions such as 'dataFromRows' or+'dataFromJson'. These can be later referred to using 'dataFromSource'.++@+let toJS = Data.Aeson.toJSON+    obj = Data.Aeson.object++    data = dataFromRows []+            . dataRow [ ( "cat", Str "a" ), ( "val", Number 10 ) ]+            . dataRow [ ( "cat", Str "b" ), ( "val", Number 18 ) ]+    json = toJS+            [ obj [ ( "cat", toJS "a" ), ( "val", toJS 120 ) ]+            , obj [ ( "cat", toJS "b" ), ( "val", toJS 180 ) ]+            ]++    enc = ...++in toVegaLite+    [ datasets [ ( "myData", data [] ),  ( "myJson", dataFromJson json [] ) ]+    , dataFromSource "myData" []+    , mark Bar []+    , enc []+    ]+@+-}+datasets :: [(T.Text, Data)] -> Data+datasets namedData =+  -- follow Elm in parsing the structure to get what we want, but the code is+  -- written rather differently+  --+  -- The input is expected to be a singleton list containing a pair.+  let convert = extract . snd +      specs = map (second convert) namedData++      extract din =+        let extract' :: [(T.Text, Value)] -> Value+            extract' [(_, v)] = v+            extract' _ = din++        in maybe din extract' (decode (encode din))+                  +  in (VLDatasets, object specs)+++{-|++Declare a data source from a provided list of column values. Each column contains+values of the same type, but columns each with a different type are permitted.+Columns should all contain the same number of items; if not the dataset will be+truncated to the length of the shortest column. An optional list of field formatting+instructions can be provided as the first parameter or an empty list to use the+default formatting. See the+<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>+for details. The columns themselves are most easily generated with 'dataColumn'++@+data =+    dataFromColumns [ Parse [ ( \"Year\", FoDate "%Y" ) ] ]+        . dataColumn \"Animal\" (Strings [ \"Fish\", \"Dog\", \"Cat\" ])+        . dataColumn \"Age\" (Numbers [ 28, 12, 6 ])+        . dataColumn \"Year\" (Strings [ "2010", "2014", "2015" ])+@+-}+dataFromColumns :: [Format] -> [DataColumn] -> Data+dataFromColumns fmts cols =+  let dataArray = map object (transpose cols)++      vals = [("values", toJSON dataArray)]+             <> if null fmts+                then []+                else [("format", toJSON fmtObject)]++      fmtObject = object (concatMap formatProperty fmts)+      +  in (VLData, object vals)+++transpose :: [[a]] -> [[a]]+transpose [] = []+transpose ([]:xss) = transpose xss+transpose ((x:xs) : xss) =+  let heads = filterMap elmHead xss --+      tails = filterMap elmTail xss++      elmHead (h:_) = Just h+      elmHead [] = Nothing++      elmTail [] = Nothing+      elmTail (_:ts) = Just ts++      filterMap = mapMaybe+      +  in (x : heads) : transpose (xs : tails)+++{-|++Declare a data source from a provided json specification. The most likely use-case+for specifying json inline is when creating <http://geojson.org geojson> objects,+when 'geometry', 'geometryCollection', and 'geoFeatureCollection' functions+may be used. For more general cases of json creation, consider 'Data.Aeson.encode'.++@+let geojson =+        geometry (GeoPolygon [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []+in toVegaLite+    [ width 200+    , height 200+    , dataFromJson geojson []+    , projection [ PType Orthographic ]+    , mark Geoshape []+    ]+@+-}+dataFromJson :: VLSpec -> [Format] -> Data+dataFromJson vlspec fmts =+  let js = if null fmts+           then object [("values", vlspec)]+           else object [ ("values", vlspec)+                       , ("format",+                          object (concatMap formatProperty fmts)) ]+  in (VLData, js)+++{-|++A single data value. This is used when a function can accept values of different+types (e.g. either a number or a string).+-}+data DataValue+    = Boolean Bool+    | DateTime [DateTime]+    | Number Double+    | Str T.Text+++dataValueSpec :: DataValue -> VLSpec+dataValueSpec (Boolean b) = toJSON b+dataValueSpec (DateTime dt) = object (map dateTimeProperty dt)+dataValueSpec (Number x) = toJSON x+dataValueSpec (Str t) = toJSON t+++{-|++A list of data values. This is used when a function can accept lists of+different types (e.g. either a list of numbers or a list of strings).+-}+data DataValues+    = Booleans [Bool]+    | DateTimes [[DateTime]]+    | Numbers [Double]+    | Strings [T.Text]+++{-|++Create a column of data. A column has a name and a list of values. The final+parameter is the list of any other columns to which this is added.++@+dataColumn \"Animal\" (Strings [ \"Cat\", \"Dog\", \"Mouse\"]) []+@+-}+dataColumn :: T.Text -> DataValues -> [DataColumn] -> [DataColumn]+dataColumn colName dVals xs =+  let col = case dVals of+        Booleans cs -> map toJSON cs+        DateTimes cs -> map dtToJSON cs+        Numbers cs -> map toJSON cs+        Strings cs -> map toJSON cs++      dtToJSON = object . map dateTimeProperty+      x = map (colName,) col+      +  in x : xs+++{-|++Declare a data source from a provided list of row values. Each row contains+a list of tuples where the first value is a string representing the column name, and the+second the column value for that row. Each column can have a value of a different type+but you must ensure that when subsequent rows are added, they match the types of previous+values with shared column names. An optional list of field formatting instructions can+be provided as the first parameter or an empty list to use the default formatting. See the+<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>+for details.++The rows themselves are most easily generated with 'dataRow'. Note though that generally+if you are creating data inline (as opposed to reading from a file), adding data by column+is more efficient and less error-prone.++@+data = dataFromRows [ Parse [ ( \"Year\", FoDate "%Y" ) ] ]+        . dataRow [ ( \"Animal\", Str \"Fish\" ), ( \"Age\", Number 28 ), ( \"Year\", Str "2010" ) ]+        . dataRow [ ( \"Animal\", Str \"Dog\" ), ( \"Age\", Number 12 ), ( \"Year\", Str "2014" ) ]+        . dataRow [ ( \"Animal\", Str \"Cat\" ), ( \"Age\", Number 6 ), ( \"Year\", Str "2015" ) ]+@+-}+dataFromRows :: [Format] -> [DataRow] -> Data+dataFromRows fmts rows =+  let kvs = ("values", toJSON rows)+            : if null fmts+              then []+              else [("format", object (concatMap formatProperty fmts))]+  in (VLData, object kvs)+++{-|++Declare data from a named source. The source may be from named 'datasets' within+a specification or a named data source created via the+<https://vega.github.io/vega/docs/api/view/#data Vega View API>.+An optional list of field formatting instructions can be provided as the second+parameter or an empty list to use the default formatting. See the+<https://vega.github.io/vega-lite/docs/data.html#named Vega-Lite documentation>+for details.++@+toVegaLite+    [ datasets [ ( "myData", data [] ),  ( "myJson", dataFromJson json [] ) ]+    , dataFromSource "myData" []+    , mark Bar []+    , enc []+    ]+@+-}+dataFromSource :: T.Text -> [Format] -> Data+dataFromSource sourceName fmts =+  let kvs = ("name" .= sourceName)+            : if null fmts+              then []+              else [("format", object (concatMap formatProperty fmts))]+  in (VLData, object kvs)+++{-|++Declare data source from a url. The url can be a local path on a web server+or an external http(s) url. Used to create a data ( property, specification ) pair.+An optional list of field formatting instructions can be provided as the second+parameter or an empty list to use the default formatting. See the+<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>+for details.++@+toVegaLite+    [ dataFromUrl "data/weather.csv" [ Parse [ ( "date", FoDate "%Y-%m-%d %H:%M" ) ] ]+    , mark Line []+    , enc []+    ]+@+-}+-- TODO: should use a URL type+dataFromUrl :: T.Text -> [Format] -> Data+dataFromUrl url fmts =+  let kvs = ("url" .= url)+            : if null fmts+              then []+              else [("format", object (concatMap formatProperty fmts))]+  in (VLData, object kvs)+++-- | Type of visual mark used to represent data in the visualization.+data Mark+    = Area+    | Bar+    | Circle+    | Geoshape+    | Line+    | Point+    | Rect+    | Rule+    | Square+    | Text+    | Tick+++markLabel :: Mark -> T.Text+markLabel Area = "area"+markLabel Bar = "bar"+markLabel Circle = "circle"+markLabel Line = "line"+markLabel Geoshape = "geoshape"+markLabel Point = "point"+markLabel Rect = "rect"+markLabel Rule = "rule"+markLabel Square = "square"+markLabel Text = "text"+markLabel Tick = "tick"+++{-|++Create a mark specification. All marks must have a type (first parameter) and+can optionally be customised with a list of mark properties such as interpolation+style for lines. To keep the default style for the mark, just provide an empty list+for the second parameter.++@+mark Circle []+mark Line [ MInterpolate StepAfter ]+@+-}+mark :: Mark -> [MarkProperty] -> (VLProperty, VLSpec)+mark mrk props =+  let jsName = toJSON (markLabel mrk)+      vals = if null props+             then jsName+             else object (("type" .= jsName) : map markProperty props)+                  +  in (VLMark, vals)+++{-|++Mark channel properties used for creating a mark channel encoding.+-}+data MarkChannel+    = MName T.Text+    | MRepeat Arrangement+    | MmType Measurement+    | MScale [ScaleProperty]+      -- ^ Use an empty list to remove the scale.+    | MBin [BinProperty]+    | MTimeUnit TimeUnit+    | MAggregate Operation+    | MLegend [LegendProperty]+      -- ^ Use an empty list to remove the legend.+    | MSelectionCondition BooleanOp [MarkChannel] [MarkChannel]+    | MDataCondition BooleanOp [MarkChannel] [MarkChannel]+    | MPath T.Text+    | MNumber Double+    | MString T.Text+    | MBoolean Bool+++markChannelProperty :: MarkChannel -> [LabelledSpec]+markChannelProperty (MName s) = [field_ s]+markChannelProperty (MRepeat arr) = ["field" .= object [repeat_ arr]]+markChannelProperty (MmType t) = [type_ t]+markChannelProperty (MScale sps) =+  [("scale", if null sps then A.Null else object (map scaleProperty sps))]+markChannelProperty (MLegend lps) =+  [("legend", if null lps then A.Null else object (map legendProperty lps))]+markChannelProperty (MBin bps) = [bin bps]+markChannelProperty (MSelectionCondition selName ifClause elseClause) =+  let h = ("condition", hkey)+      toProps = concatMap markChannelProperty+      hkey = object (("selection", booleanOpSpec selName) : toProps ifClause)+      hs = toProps elseClause+  in h : hs+markChannelProperty (MDataCondition predicate ifClause elseClause) =+  let h = ("condition", hkey)+      toProps = concatMap markChannelProperty+      hkey = object (("test", booleanOpSpec predicate) : toProps ifClause)+      hs = toProps elseClause+  in h : hs+markChannelProperty (MTimeUnit tu) = [timeUnit_ tu]+markChannelProperty (MAggregate op) = [aggregate_ op]+markChannelProperty (MPath s) = ["value" .= s]+markChannelProperty (MNumber x) = ["value" .= x]+markChannelProperty (MString s) = ["value" .= s]+markChannelProperty (MBoolean b) = ["value" .= b]+++{-|++Properties for customising the appearance of a mark. For details see the+<https://vega.github.io/vega-lite/docs/mark.html#config Vega-Lite documentation>.++Not all properties are valid for each mark type.+-}+data MarkProperty+    = MAlign HAlign+    | MAngle Double+    | MBandSize Double+    | MBaseline VAlign+    | MBinSpacing Double+    | MClip Bool+    | MColor T.Text+    | MCursor Cursor+    | MContinuousBandSize Double+    | MDiscreteBandSize Double+    | MdX Double+    | MdY Double+    | MFill T.Text+    | MFilled Bool+    | MFillOpacity Double+    | MFont T.Text+    | MFontSize Double+    | MFontStyle T.Text+    | MFontWeight FontWeight+    | MInterpolate MarkInterpolation+    | MOpacity Double+    | MOrient MarkOrientation+    | MRadius Double+    | MShape Symbol+    | MShortTimeLabels Bool+    | MSize Double+    | MStroke T.Text+    | MStrokeDash [Double]+    | MStrokeDashOffset Double+    | MStrokeOpacity Double+    | MStrokeWidth Double+    | MStyle [T.Text]+    | MTension Double+    | MText T.Text+    | MTheta Double+    | MThickness Double+++markProperty :: MarkProperty -> LabelledSpec+markProperty (MFilled b) = ("filled", toJSON b)+markProperty (MClip b) = ("clip", toJSON b)+markProperty (MColor col) = ("color", toJSON col)+markProperty (MCursor cur) = ("cursor", toJSON (cursorLabel cur))+markProperty (MFill col) = ("fill", toJSON col)+markProperty (MStroke t) = ("stroke", toJSON t)+markProperty (MStrokeOpacity x) = ("strokeOpacity", toJSON x)+markProperty (MStrokeWidth w) = ("strokeWidth", toJSON w)+markProperty (MStrokeDash xs) = ("strokeDash", toJSON (map toJSON xs))+markProperty (MStrokeDashOffset x) = ("strokeDashOffset", toJSON x)+markProperty (MOpacity x) = ("opacity", toJSON x)+markProperty (MFillOpacity x) = ("fillOpacity", toJSON x)+markProperty (MStyle styles) = ("style", toJSON (map toJSON styles))+markProperty (MInterpolate interp) = ("interpolate", toJSON (markInterpolationLabel interp))+markProperty (MTension x) = ("tension", toJSON x)+markProperty (MOrient orient) = ("orient", toJSON (markOrientationLabel orient))+markProperty (MShape sym) = ("shape", toJSON (symbolLabel sym))+markProperty (MSize x) = ("size", toJSON x)+markProperty (MAngle x) = ("angle", toJSON x)+markProperty (MAlign align) = ("align", toJSON (hAlignLabel align))+markProperty (MBaseline va) = ("baseline", toJSON (vAlignLabel va))+markProperty (MdX dx) = ("dx", toJSON dx)+markProperty (MdY dy) = ("dy", toJSON dy)+markProperty (MFont fnt) = ("font", toJSON fnt)+markProperty (MFontSize x) = ("fontSize", toJSON x)+markProperty (MFontStyle fSty) = ("fontStyle", toJSON fSty)+markProperty (MFontWeight w) = ("fontWeight", fontWeightSpec w)+markProperty (MRadius x) = ("radius", toJSON x)+markProperty (MText txt) = ("text", toJSON txt)+markProperty (MTheta x) = ("theta", toJSON x)+markProperty (MBinSpacing x) = ("binSpacing", toJSON x)+markProperty (MContinuousBandSize x) = ("continuousBandSize", toJSON x)+markProperty (MDiscreteBandSize x) = ("discreteBandSize", toJSON x)+markProperty (MShortTimeLabels b) = ("shortTimeLabels", toJSON b)+markProperty (MBandSize x) = ("bandSize", toJSON x)+markProperty (MThickness x) = ("thickness", toJSON x)+++{-|++Create an encoding specification from a list of channel encodings.++@+enc = encoding+        . position X [ PName \"Animal\", PmType Ordinal ]+        . position Y [ PName \"Age\", PmType Quantitative ]+        . shape [ MName \"Species\", MmType Nominal ]+        . size [ MName \"Population\", MmType Quantitative ]+@+-}+encoding :: [LabelledSpec] -> (VLProperty, VLSpec)+encoding channels = (VLEncoding, object channels)+++{-|++Type of position channel, @X@ and @Y@ represent horizontal and vertical axis+dimensions on a plane and @X2@ and @Y2@ represent secondary axis dimensions where+two scales are overlaid in the same space. Geographic positions represented by+longitude and latiutude values are identified with @Longitude@, @Latitude@ and+their respective secondary equivalents. Such geographic position channels are+subject to a map projection (set using 'projection') before being placed graphically.+-}+data Position+    = X+    | Y+    | X2+    | Y2+    | Longitude+    | Latitude+    | Longitude2+    | Latitude2+++{-|++Type of measurement to be associated with some channel.++-}++data Measurement+    = Nominal+      -- ^ Data are categories identified by name alone and which have no intrinsic order.+    | Ordinal+      -- ^ Data are also categories, but ones which have some natural order.+    | Quantitative+      -- ^ Data are numeric measurements typically on a continuous scale.+    | Temporal+      -- ^ Data represents time in some manner.+    | GeoFeature+      -- ^ Geospatial position encoding ('Longitude' and 'Latitude') should specify the 'PmType'+      -- as @Quantitative@. Geographically referenced features encoded as 'shape' marks+      -- should specify 'MmType' as @GeoFeature@ (Vega-Lite currently refers to this type+      -- as @<https://vega.github.io/vega-lite/docs/encoding.html geojson>@.+++{-|++Type of binning property to customise. See the+<https://vega.github.io/vega-lite/docs/bin.html Vega-Lite documentation> for+more details.+-}++data BinProperty+    = Base Double+    | Divide Double Double+    | Extent Double Double+    | MaxBins Int+    | MinStep Double+    | Nice Bool+    | Step Double+    | Steps [Double]+++binProperty :: BinProperty -> LabelledSpec+binProperty (MaxBins n) = ("maxbins", toJSON n)+binProperty (Base x) = ("base", toJSON x)+binProperty (Step x) = ("step", toJSON x)+binProperty (Steps xs) = ("steps", toJSON (map toJSON xs))+binProperty (MinStep x) = ("minstep", toJSON x)+binProperty (Divide x y) = ("divide", toJSON [ toJSON x, toJSON y ])+binProperty (Extent mn mx) = ("extent", toJSON [ toJSON mn, toJSON mx ])+binProperty (Nice b) = ("nice", toJSON b)+++bin :: [BinProperty] -> LabelledSpec+bin bProps =+  let ans = if null bProps+            then toJSON True+            else object (map binProperty bProps)+  in ("bin", ans)+++{-|++Type of aggregation operation. See the+<https://vega.github.io/vega-lite/docs/aggregate.html#ops Vega-Lite documentation>+for more details.+-}+data Operation+    = ArgMax+    | ArgMin+    | Average+    | CI0+    | CI1+    | Count+    | Distinct+    | Max+    | Mean+    | Median+    | Min+    | Missing+    | Q1+    | Q3+    | Stderr+    | Stdev+    | StdevP+    | Sum+    | Valid+    | Variance+    | VarianceP+++operationLabel :: Operation -> T.Text+operationLabel ArgMax = "argmax"+operationLabel ArgMin = "argmin"+operationLabel Average = "average"+operationLabel CI0 = "ci0"+operationLabel CI1 = "ci1"+operationLabel Count = "count"+operationLabel Distinct = "distinct"+operationLabel Max = "max"+operationLabel Mean = "mean"+operationLabel Median = "median"+operationLabel Min = "min"+operationLabel Missing = "missing"+operationLabel Q1 = "q1"+operationLabel Q3 = "q3"+operationLabel Stderr = "stderr"+operationLabel Stdev = "stdev"+operationLabel StdevP = "stdevp"+operationLabel Sum = "sum"+operationLabel Valid = "valid"+operationLabel Variance = "variance"+operationLabel VarianceP = "variancep"+++-- | Identifies whether a repeated or faceted view is arranged in rows or columns.++data Arrangement+    = Column+    | Row++arrangementLabel :: Arrangement -> T.Text+arrangementLabel Column = "column"+arrangementLabel Row = "row"+++-- | Describes the type of stacking to apply to a bar chart.++data StackProperty+    = StZero+    | StNormalize+    | StCenter+    | NoStack+++stackProperty :: StackProperty -> LabelledSpec+stackProperty StZero = ("stack", "zero")+stackProperty StNormalize = ("stack", "normalize")+stackProperty StCenter = ("stack", "center")+stackProperty NoStack = ("stack", A.Null)+++{-|++Individual scale property. These are used to customise an individual scale+transformation. To customise all scales use 'config' and supply relevant+'ScaleConfig' values. For more details see the+<https://vega.github.io/vega-lite/docs/scale.html Vega-Lite documentation>.++-}++data ScaleProperty+    = SType Scale+    | SDomain ScaleDomain+    | SRange ScaleRange+    | SScheme T.Text [Double]+    | SPadding Double+    | SPaddingInner Double+    | SPaddingOuter Double+    | SRangeStep (Maybe Double)+    | SRound Bool+    | SClamp Bool+      -- TODO:  Need to restrict set of valid scale types that work with color interpolation.+    | SInterpolate CInterpolate+    | SNice ScaleNice+    | SZero Bool+      -- TODO: Check: This is a Vega, not Vega-Lite property so can generate a warning if validated against the Vega-Lite spec.+    | SReverse Bool+++scaleProperty :: ScaleProperty -> LabelledSpec+scaleProperty (SType sType) = ("type", toJSON (scaleLabel sType))+scaleProperty (SDomain sdType) = ("domain", scaleDomainSpec sdType)+scaleProperty (SRange range) =+  let js = case range of+        RNumbers xs -> toJSON (map toJSON xs)+        RStrings ss -> toJSON (map toJSON ss)+        RName s -> toJSON s+  in ("range", js)+scaleProperty (SScheme nme extent) = schemeProperty nme extent+scaleProperty (SPadding x) = ("padding", toJSON x)+scaleProperty (SPaddingInner x) = ("paddingInner", toJSON x)+scaleProperty (SPaddingOuter x) = ("paddingOuter", toJSON x)+scaleProperty (SRangeStep numOrNull) = ("rangeStep", maybe A.Null toJSON numOrNull)+scaleProperty (SRound b) = ("round", toJSON b)+scaleProperty (SClamp b) = ("clamp", toJSON b)+scaleProperty (SInterpolate interp) = ("interpolate", cInterpolateSpec interp)+scaleProperty (SNice ni) = ("nice", scaleNiceSpec ni)+scaleProperty (SZero b) = ("zero", toJSON b)+scaleProperty (SReverse b) = ("reverse", toJSON b)+++schemeProperty :: T.Text -> [Double] -> LabelledSpec+schemeProperty nme extent =+  let js = case extent of+        [mn, mx] -> object ["name" .= nme, "extent" .= [mn, mx]]+        _ -> toJSON nme+        +  in ("scheme", js)+++-- | Used to indicate the type of scale transformation to apply.++data Scale+    = ScLinear+    | ScPow+    | ScSqrt+    | ScLog+    | ScTime+    | ScUtc+    | ScSequential+    | ScOrdinal+    | ScBand+    | ScPoint+    | ScBinLinear+    | ScBinOrdinal+++scaleLabel :: Scale -> T.Text+scaleLabel ScLinear = "linear"+scaleLabel ScPow = "pow"+scaleLabel ScSqrt = "sqrt"+scaleLabel ScLog = "log"+scaleLabel ScTime = "time"+scaleLabel ScUtc = "utc"+scaleLabel ScSequential = "sequential"+scaleLabel ScOrdinal = "ordinal"+scaleLabel ScBand = "band"+scaleLabel ScPoint = "point"+scaleLabel ScBinLinear = "bin-linear"+scaleLabel ScBinOrdinal = "bin-ordinal"+++{-|++Describes the scale domain (type of data in scale). For full details see the+<https://vega.github.io/vega-lite/docs/scale.html#domain Vega-Lite documentation>.+-}++data ScaleDomain+    = DNumbers [Double]+    | DStrings [T.Text]+    | DDateTimes [[DateTime]]+    | DSelection T.Text+    | Unaggregated+++scaleDomainSpec :: ScaleDomain -> VLSpec+scaleDomainSpec (DNumbers nums) = toJSON (map toJSON nums)+scaleDomainSpec (DDateTimes dts) = toJSON (map (object . map dateTimeProperty) dts)+scaleDomainSpec (DStrings cats) = toJSON (map toJSON cats)+scaleDomainSpec (DSelection selName) = object ["selection" .= selName]+scaleDomainSpec Unaggregated = "unaggregated"+++{-|++Describes the way a scale can be rounded to \"nice\" numbers. For full details see the+<https://vega.github.io/vega-lite/docs/scale.html#continuous Vega-Lite documentation>.+-}+data ScaleNice+    = NMillisecond+    | NSecond+    | NMinute+    | NHour+    | NDay+    | NWeek+    | NMonth+    | NYear+    | NInterval TimeUnit Int+    | IsNice Bool+    | NTickCount Int+++scaleNiceSpec :: ScaleNice -> VLSpec+scaleNiceSpec NMillisecond = fromT "millisecond"+scaleNiceSpec NSecond = fromT "second"+scaleNiceSpec NMinute = fromT "minute"+scaleNiceSpec NHour = fromT "hour"+scaleNiceSpec NDay = fromT "day"+scaleNiceSpec NWeek = fromT "week"+scaleNiceSpec NMonth = fromT "month"+scaleNiceSpec NYear = fromT "year"+scaleNiceSpec (NInterval tu step) =+  object ["interval" .= timeUnitLabel tu, "step" .= step]+scaleNiceSpec (IsNice b) = toJSON b+scaleNiceSpec (NTickCount n) = toJSON n+++{-|++Describes a scale range of scale output values. For full details see the+<https://vega.github.io/vega-lite/docs/scale.html#range Vega-Lite documentation>.+-}++data ScaleRange+    = RNumbers [Double]+    | RStrings [T.Text]+    | RName T.Text+++{-|++Indicates the type of color interpolation to apply, when mapping a data field+onto a color scale. Note that color interpolation cannot be applied with the default+\"sequential\" color scale ('ScSequential'), so additionally, you should set the+'SType' to another continuous scale such as 'ScLinear' and 'ScPow'.++For details see the+<https://vega.github.io/vega-lite/docs/scale.html#continuous Vega-Lite documentation>.+-}+data CInterpolate+    = CubeHelix Double+      -- ^ The numeric value is the gamma value for the scheme (the recommended+      --   value is 1).+    | CubeHelixLong Double+      -- ^ The numeric value is the gamma value for the scheme (the recommended+      --   value is 1).+    | Hcl+    | HclLong+    | Hsl+    | HslLong+    | Lab+    | Rgb Double+      -- ^ The numeric value is the gamma value for the scheme (the recommended+      --   value is 1).+++-- Need to tie down some types as things are too polymorphic,+-- particularly in the presence of OverloadedStrings.+--+pairT :: T.Text -> T.Text -> (T.Text, Value)+pairT a b = a .= b+++cInterpolateSpec :: CInterpolate -> VLSpec+cInterpolateSpec (Rgb gamma) = object [pairT "type" "rgb", "gamma" .= gamma]+cInterpolateSpec Hsl = object [pairT "type" "hsl"]+cInterpolateSpec HslLong = object [pairT "type" "hsl-long"]+cInterpolateSpec Lab = object [pairT "type" "lab"]+cInterpolateSpec Hcl = object [pairT "type" "hcl"]+cInterpolateSpec HclLong = object [pairT "type" "hcl-long"]+cInterpolateSpec (CubeHelix gamma) = object [pairT "type" "cubehelix", "gamma" .= gamma]+cInterpolateSpec (CubeHelixLong gamma) = object [pairT "type" "cubehelix-long", "gamma" .= gamma]+++{-|++Allow type of sorting to be customised. For details see the+<https://vega.github.io/vega-lite/docs/sort.html Vega-Lite documentation>.+-}+data SortProperty+    = Ascending+    | Descending+    | Op Operation+    | ByField T.Text+    | ByRepeat Arrangement+++sortProperty :: SortProperty -> LabelledSpec+sortProperty Ascending = "order" .= fromT "ascending"+sortProperty Descending = "order" .= fromT "descending"+sortProperty (ByField field) = field_ field+sortProperty (Op op) = op_ op+sortProperty (ByRepeat arr) = ("field", object [repeat_ arr])+++sortPropertySpec :: [SortProperty] -> VLSpec+sortPropertySpec [] = A.Null+sortPropertySpec [Ascending] = fromT "ascending"+sortPropertySpec [Descending] = fromT "descending"+sortPropertySpec ops = object (map sortProperty ops)+++-- | Position channel properties used for creating a position channel encoding.++data PositionChannel+    = PName T.Text+    | PRepeat Arrangement+    | PmType Measurement+    | PBin [BinProperty]+    | PTimeUnit TimeUnit+    | PAggregate Operation+    | PScale [ScaleProperty]+    | PAxis [AxisProperty]+    | PSort [SortProperty]+    | PStack StackProperty+++positionChannelProperty :: PositionChannel -> LabelledSpec+positionChannelProperty (PName s) = field_ s+positionChannelProperty (PRepeat arr) = "field" .= object [repeat_ arr]+positionChannelProperty (PmType m) = type_ m+positionChannelProperty (PBin b) = bin b+positionChannelProperty (PTimeUnit tu) = timeUnit_ tu+positionChannelProperty (PAggregate op) = aggregate_ op+positionChannelProperty (PScale sps) =+  let js = if null sps+           then A.Null+           else object (map scaleProperty sps)+  in "scale" .=  js+positionChannelProperty (PAxis aps) =+  let js = if null aps+           then A.Null+           else object (map axisProperty aps)+  in "axis" .= js+positionChannelProperty (PSort ops) = sort_ ops+positionChannelProperty (PStack sp) = stackProperty sp+++measurementLabel :: Measurement -> T.Text+measurementLabel Nominal = "nominal"+measurementLabel Ordinal = "ordinal"+measurementLabel Quantitative = "quantitative"+measurementLabel Temporal = "temporal"+measurementLabel GeoFeature = "geojson"+++positionLabel :: Position -> T.Text+positionLabel X = "x"+positionLabel Y = "y"+positionLabel X2 = "x2"+positionLabel Y2 = "y2"+positionLabel Longitude = "longitude"+positionLabel Latitude = "latitude"+positionLabel Longitude2 = "longitude2"+positionLabel Latitude2 = "latitude2"+++{-|++Set the background color of the visualization. Should be specified with a CSS+string such as \"#ffe\" or \"rgb(200,20,150)\". If not specified the background will+be transparent.++@+toVegaLite+    [ background "rgb(251,247,238)"+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+background :: T.Text -> (VLProperty, VLSpec)+background colour = (VLBackground, toJSON colour)+++{-|++Provides an optional description to be associated with the visualization.++@+toVegaLite+    [ description "Population change of key regions since 1900"+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+description :: T.Text -> (VLProperty, VLSpec)+description s = (VLDescription, toJSON s)+++{-|++Provide an optional title to be displayed in the visualization.++@+toVegaLite+    [ title "Population Growth"+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+title :: T.Text -> (VLProperty, VLSpec)+title s = (VLTitle, toJSON s)+++{-|++Axis customisation properties. These are used for customising individual axes.+To configure all axes, use 'AxisConfig' with a 'configuration' instead. See the+<https://vega.github.io/vega-lite/docs/axis.html#axis-properties Vega-Lite documentation>+for more details.+-}+data AxisProperty+    = AxDomain Bool+    | AxFormat T.Text+    | AxGrid Bool+    | AxLabelAngle Double+    | AxLabelOverlap OverlapStrategy+    | AxLabelPadding Double+    | AxLabels Bool+    | AxMaxExtent Double+    | AxMinExtent Double+    | AxOffset Double+    | AxOrient Side+    | AxPosition Double+    | AxTicks Bool+    | AxTickCount Int+    | AxTickSize Double+    | AxTitle T.Text+    | AxTitleAlign HAlign+    | AxTitleAngle Double+    | AxTitleMaxLength Double+    | AxTitlePadding Double+    | AxValues [Double]+    | AxDates [[DateTime]]+    | AxZIndex Int+++axisProperty :: AxisProperty -> LabelledSpec+axisProperty (AxFormat fmt) = "format" .= fmt+axisProperty (AxLabels b) = "labels" .= b+axisProperty (AxLabelAngle a) = "labelAngle" .= a+axisProperty (AxLabelOverlap s) = "labelOverlap" .= overlapStrategyLabel s+axisProperty (AxLabelPadding pad) = "labelPadding" .= pad+axisProperty (AxDomain b) = "domain" .= b+axisProperty (AxGrid b) = "grid" .= b+axisProperty (AxMaxExtent n) = "maxExtent" .= n+axisProperty (AxMinExtent n) = "minExtent" .= n+axisProperty (AxOrient side) = "orient" .= sideLabel side+axisProperty (AxOffset n) = "offset" .= n+axisProperty (AxPosition n) = "position" .= n+axisProperty (AxZIndex n) = "zindex" .= n+axisProperty (AxTicks b) = "ticks" .= b+axisProperty (AxTickCount n) = "tickCount" .= n+axisProperty (AxTickSize sz) = "tickSize" .= sz+axisProperty (AxValues vals) = "values" .= map toJSON vals+axisProperty (AxDates dtss) = "values" .= map (object . map dateTimeProperty) dtss+axisProperty (AxTitle ttl) = "title" .= ttl+axisProperty (AxTitleAlign align) = "titleAlign" .= hAlignLabel align+axisProperty (AxTitleAngle angle) = "titleAngle" .= angle+axisProperty (AxTitleMaxLength len) = "titleMaxLength" .= len+axisProperty (AxTitlePadding pad) = "titlePadding" .= pad+++-- | Indicates the horizontal alignment of text such as on an axis or legend.++data HAlign+    = AlignCenter+    | AlignLeft+    | AlignRight+++-- | Indicates the vertical alignment of text that may be attached to a mark.++data VAlign+    = AlignTop+    | AlignMiddle+    | AlignBottom+++hAlignLabel :: HAlign -> T.Text+hAlignLabel AlignLeft = "left"+hAlignLabel AlignCenter = "center"+hAlignLabel AlignRight = "right"+++vAlignLabel :: VAlign -> T.Text+vAlignLabel AlignTop = "top"+vAlignLabel AlignMiddle = "middle"+vAlignLabel AlignBottom = "bottom"+++-- | Represents one side of a rectangular space.++data Side+    = STop+    | SBottom+    | SLeft+    | SRight+++sideLabel :: Side -> T.Text+sideLabel STop = "top"+sideLabel SBottom = "bottom"+sideLabel SLeft = "left"+sideLabel SRight = "right"+++{-|++Type of overlap strategy to be applied when there is not space to show all items+on an axis. See the+<https://vega.github.io/vega-lite/docs/axis.html#labels Vega-Lite documentation>+for more details.+-}++data OverlapStrategy+    = ONone+    | OParity+    | OGreedy+++overlapStrategyLabel :: OverlapStrategy -> T.Text+overlapStrategyLabel ONone = "false"+overlapStrategyLabel OParity = "parity"+overlapStrategyLabel OGreedy = "greedy"+++{-|++Allows a date or time to be represented. This is typically part of a list of+@DateTime@ items to provide a specific point in time. For details see the+<https://vega.github.io/vega-lite/docs/types.html#datetime Vega-Lite documentation>.+-}++data DateTime+    = DTYear Int+    | DTQuarter Int+    | DTMonth MonthName+    | DTDate Int+    | DTDay DayName+    | DTHours Int+    | DTMinutes Int+    | DTSeconds Int+    | DTMilliseconds Int+++-- | Identifies the day of the week.++data DayName+    = Mon+    | Tue+    | Wed+    | Thu+    | Fri+    | Sat+    | Sun+++-- | Identifies a month of the year.++data MonthName+    = Jan+    | Feb+    | Mar+    | Apr+    | May+    | Jun+    | Jul+    | Aug+    | Sep+    | Oct+    | Nov+    | Dec+++{-|++Describes a unit of time. Useful for encoding and transformations. See the+<https://vega.github.io/vega-lite/docs/timeunit.html Vega-Lite documentation>+for further details.++@+encoding+    . position X [ PName "date", PmType Temporal, PTimeUnit (Utc YearMonthDateHours) ]+@+-}++data TimeUnit+    = Year+    | YearQuarter+    | YearQuarterMonth+    | YearMonth+    | YearMonthDate+    | YearMonthDateHours+    | YearMonthDateHoursMinutes+    | YearMonthDateHoursMinutesSeconds+    | Quarter+    | QuarterMonth+    | Month+    | MonthDate+    | Date+    | Day+    | Hours+    | HoursMinutes+    | HoursMinutesSeconds+    | Minutes+    | MinutesSeconds+    | Seconds+    | SecondsMilliseconds+    | Milliseconds+    | Utc TimeUnit+      -- ^ Encode a time as UTC (coordinated universal time, independent of local time+      --   zones or daylight saving).+++dateTimeProperty :: DateTime -> LabelledSpec+dateTimeProperty (DTYear y) = "year" .= y+dateTimeProperty (DTQuarter q) = "quarter" .= q+dateTimeProperty (DTMonth mon) = "month" .= monthNameLabel mon+dateTimeProperty (DTDate dt) = "date" .= dt+dateTimeProperty (DTDay day) = "day" .= dayLabel day+dateTimeProperty (DTHours h) = "hours" .= h+dateTimeProperty (DTMinutes m) = "minutes" .= m+dateTimeProperty (DTSeconds s) = "seconds" .= s+dateTimeProperty (DTMilliseconds ms) = "milliseconds" .= ms+++dayLabel :: DayName -> T.Text+dayLabel Mon = "Mon"+dayLabel Tue = "Tue"+dayLabel Wed = "Wed"+dayLabel Thu = "Thu"+dayLabel Fri = "Fri"+dayLabel Sat = "Sat"+dayLabel Sun = "Sun"+++monthNameLabel :: MonthName -> T.Text+monthNameLabel Jan = "Jan"+monthNameLabel Feb = "Feb"+monthNameLabel Mar = "Mar"+monthNameLabel Apr = "Apr"+monthNameLabel May = "May"+monthNameLabel Jun = "Jun"+monthNameLabel Jul = "Jul"+monthNameLabel Aug = "Aug"+monthNameLabel Sep = "Sep"+monthNameLabel Oct = "Oct"+monthNameLabel Nov = "Nov"+monthNameLabel Dec = "Dec"+++timeUnitLabel :: TimeUnit -> T.Text+timeUnitLabel Year = "year"+timeUnitLabel YearQuarter = "yearquarter"+timeUnitLabel YearQuarterMonth = "yearquartermonth"+timeUnitLabel YearMonth = "yearmonth"+timeUnitLabel YearMonthDate = "yearmonthdate"+timeUnitLabel YearMonthDateHours = "yearmonthdatehours"+timeUnitLabel YearMonthDateHoursMinutes = "yearmonthdatehoursminutes"+timeUnitLabel YearMonthDateHoursMinutesSeconds = "yearmonthdatehoursminutesseconds"+timeUnitLabel Quarter = "quarter"+timeUnitLabel QuarterMonth = "quartermonth"+timeUnitLabel Month = "month"+timeUnitLabel MonthDate = "monthdate"+timeUnitLabel Date = "date"+timeUnitLabel Day = "day"+timeUnitLabel Hours = "hours"+timeUnitLabel HoursMinutes = "hoursminutes"+timeUnitLabel HoursMinutesSeconds = "hoursminutesseconds"+timeUnitLabel Minutes = "minutes"+timeUnitLabel MinutesSeconds = "minutesseconds"+timeUnitLabel Seconds = "seconds"+timeUnitLabel SecondsMilliseconds = "secondsmilliseconds"+timeUnitLabel Milliseconds = "milliseconds"+timeUnitLabel (Utc tu) = "utc" <> timeUnitLabel tu+++{-|++Represents the type of cursor to display. For an explanation of each type,+see the+<https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#Keyword%20values CSS documentation>.+-}+data Cursor+    = CAuto+    | CDefault+    | CNone+    | CContextMenu+    | CHelp+    | CPointer+    | CProgress+    | CWait+    | CCell+    | CCrosshair+    | CText+    | CVerticalText+    | CAlias+    | CCopy+    | CMove+    | CNoDrop+    | CNotAllowed+    | CAllScroll+    | CColResize+    | CRowResize+    | CNResize+    | CEResize+    | CSResize+    | CWResize+    | CNEResize+    | CNWResize+    | CSEResize+    | CSWResize+    | CEWResize+    | CNSResize+    | CNESWResize+    | CNWSEResize+    | CZoomIn+    | CZoomOut+    | CGrab+    | CGrabbing+++cursorLabel :: Cursor -> T.Text+cursorLabel CAuto = "auto"+cursorLabel CDefault = "default"+cursorLabel CNone = "none"+cursorLabel CContextMenu = "context-menu"+cursorLabel CHelp = "help"+cursorLabel CPointer = "pointer"+cursorLabel CProgress = "progress"+cursorLabel CWait = "wait"+cursorLabel CCell = "cell"+cursorLabel CCrosshair = "crosshair"+cursorLabel CText = "text"+cursorLabel CVerticalText = "vertical-text"+cursorLabel CAlias = "alias"+cursorLabel CCopy = "copy"+cursorLabel CMove = "move"+cursorLabel CNoDrop = "no-drop"+cursorLabel CNotAllowed = "not-allowed"+cursorLabel CAllScroll = "all-scroll"+cursorLabel CColResize = "col-resize"+cursorLabel CRowResize = "row-resize"+cursorLabel CNResize = "n-resize"+cursorLabel CEResize = "e-resize"+cursorLabel CSResize = "s-resize"+cursorLabel CWResize = "w-resize"+cursorLabel CNEResize = "ne-resize"+cursorLabel CNWResize = "nw-resize"+cursorLabel CSEResize = "se-resize"+cursorLabel CSWResize = "sw-resize"+cursorLabel CEWResize = "ew-resize"+cursorLabel CNSResize = "ns-resize"+cursorLabel CNESWResize = "nesw-resize"+cursorLabel CNWSEResize = "nwse-resize"+cursorLabel CZoomIn = "zoom-in"+cursorLabel CZoomOut = "zoom-out"+cursorLabel CGrab = "grab"+cursorLabel CGrabbing = "grabbing"+++-- | Indicates the weight options for a font.++data FontWeight+    = Bold+    | Bolder+    | Lighter+    | Normal+    | W100+    | W200+    | W300+    | W400+    | W500+    | W600+    | W700+    | W800+    | W900+++fontWeightSpec :: FontWeight -> VLSpec+fontWeightSpec Bold = fromT "bold"+fontWeightSpec Bolder = fromT "bolder"+fontWeightSpec Lighter = fromT "lighter"+fontWeightSpec Normal = fromT "normal"+fontWeightSpec W100 = fromF 100+fontWeightSpec W200 = fromF 200+fontWeightSpec W300 = fromF 300+fontWeightSpec W400 = fromF 400+fontWeightSpec W500 = fromF 500+fontWeightSpec W600 = fromF 600+fontWeightSpec W700 = fromF 700+fontWeightSpec W800 = fromF 800+fontWeightSpec W900 = fromF 900+++{-|++Indicates mark interpolation style. See the+<https://vega.github.io/vega-lite/docs/mark.html#mark-def Vega-Lite documentation>+for details.+-}+data MarkInterpolation+    = Basis+    | BasisClosed+    | BasisOpen+    | Bundle+    | Cardinal+    | CardinalClosed+    | CardinalOpen+    | Linear+    | LinearClosed+    | Monotone+    | StepAfter+    | StepBefore+    | Stepwise+++markInterpolationLabel :: MarkInterpolation -> T.Text+markInterpolationLabel Linear = "linear"+markInterpolationLabel LinearClosed = "linear-closed"+markInterpolationLabel Stepwise = "step"+markInterpolationLabel StepBefore = "step-before"+markInterpolationLabel StepAfter = "step-after"+markInterpolationLabel Basis = "basis"+markInterpolationLabel BasisOpen = "basis-open"+markInterpolationLabel BasisClosed = "basis-closed"+markInterpolationLabel Cardinal = "cardinal"+markInterpolationLabel CardinalOpen = "cardinal-open"+markInterpolationLabel CardinalClosed = "cardinal-closed"+markInterpolationLabel Bundle = "bundle"+markInterpolationLabel Monotone = "monotone"+++{-|++Indicates desired orientation of a mark (e.g. horizontally or vertically+oriented bars).+-}+data MarkOrientation+    = Horizontal+    | Vertical+++markOrientationLabel :: MarkOrientation -> T.Text+markOrientationLabel Horizontal = "horizontal"+markOrientationLabel Vertical = "vertical"+++-- | Identifies the type of symbol.++data Symbol+    = SymCircle+    | SymSquare+    | Cross+    | Diamond+    | TriangleUp+    | TriangleDown+    | Path T.Text+      -- ^ Define a custom shape with a SVG path description.+++symbolLabel :: Symbol -> T.Text+symbolLabel SymCircle = "circle"+symbolLabel SymSquare = "square"+symbolLabel Cross = "cross"+symbolLabel Diamond = "diamond"+symbolLabel TriangleUp = "triangle-up"+symbolLabel TriangleDown = "triangle-down"+symbolLabel (Path svgPath) = svgPath+++{-|++Indicates the auto-sizing characteristics of the visualization such as amount+of padding, whether it should fill the parent container etc. For more details see the+<https://vega.github.io/vega-lite/docs/size.html#autosize Vega-Lite documentation>.+-}++data Autosize+    = AContent+    | AFit+    | ANone+    | APad+    | APadding+    | AResize+++autosizeProperty :: Autosize -> LabelledSpec+autosizeProperty APad = ("type", fromT "pad")+autosizeProperty AFit = ("type", fromT "fit")+autosizeProperty ANone = ("type", fromT "none")+autosizeProperty AResize = "resize".= True+autosizeProperty AContent = ("contains", fromT "content")+autosizeProperty APadding = ("contains", fromT "padding")+++{-|++Declare the way the view is sized. See the+<https://vega.github.io/vega-lite/docs/size.html#autosize Vega-Lite documentation>+for details.++@+toVegaLite+    [ width 250+    , height 300+    , autosize [ AFit, APadding, AResize ]+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+autosize :: [Autosize] -> (VLProperty, VLSpec)+autosize aus = (VLAutosize, object (map autosizeProperty aus))+++-- | Indicates the style in which field names are displayed.++data FieldTitleProperty+    = Verbal+      -- ^ Creates \"Sum of field\", \"Year of date\", \"field (binned)\", etc.+    | Function+      -- ^ Creates \"SUM(field)\", \"YEAR(date)\", \"BIN(field)\", etc.+    | Plain+      -- ^ Just use the field name without any extra text.+++fieldTitleLabel :: FieldTitleProperty -> T.Text+fieldTitleLabel Verbal = "verbal"+fieldTitleLabel Function = "function"+fieldTitleLabel Plain = "plain"+++-- | Indicates the type of legend to create.++data Legend+    = Gradient+      -- ^ Typically used for continuous quantitative data.+    | Symbol+      -- ^ Typically used for categorical data.+      ++legendLabel :: Legend -> T.Text+legendLabel Gradient = "gradient"+legendLabel Symbol = "symbol"+++{-|++Legend configuration options. For more detail see the+<https://vega.github.io/vega-lite/docs/legend.html#config Vega-Lite documentation>.+-}++data LegendConfig+    = CornerRadius Double+    | FillColor T.Text+    | Orient LegendOrientation+    | Offset Double+    | StrokeColor T.Text+    | LeStrokeDash [Double]+    | LeStrokeWidth Double+    | LePadding Double+    | GradientLabelBaseline VAlign+    | GradientLabelLimit Double+    | GradientLabelOffset Double+    | GradientStrokeColor T.Text+    | GradientStrokeWidth Double+    | GradientHeight Double+    | GradientWidth Double+    | LeLabelAlign HAlign+    | LeLabelBaseline VAlign+    | LeLabelColor T.Text+    | LeLabelFont T.Text+    | LeLabelFontSize Double+    | LeLabelLimit Double+    | LeLabelOffset Double+    | LeShortTimeLabels Bool+    | EntryPadding Double+    | SymbolColor T.Text+    | SymbolType Symbol+    | SymbolSize Double+    | SymbolStrokeWidth Double+    | LeTitleAlign HAlign+    | LeTitleBaseline VAlign+    | LeTitleColor T.Text+    | LeTitleFont T.Text+    | LeTitleFontSize Double+    | LeTitleFontWeight FontWeight+    | LeTitleLimit Double+    | LeTitlePadding Double+++legendConfigProperty :: LegendConfig -> LabelledSpec+legendConfigProperty (CornerRadius r) = "cornerRadius" .= r+legendConfigProperty (FillColor s) = "fillColor" .= s+legendConfigProperty (Orient orl) = "orient" .= legendOrientLabel orl+legendConfigProperty (Offset x) = "offset" .= x+legendConfigProperty (StrokeColor s) = "strokeColor" .= s+legendConfigProperty (LeStrokeDash xs) = "strokeDash" .= map toJSON xs+legendConfigProperty (LeStrokeWidth x) = "strokeWidth" .= x+legendConfigProperty (LePadding x) = "padding" .= x+legendConfigProperty (GradientLabelBaseline va) = "gradientLabelBaseline" .= vAlignLabel va+legendConfigProperty (GradientLabelLimit x) = "gradientLabelLimit" .= x+legendConfigProperty (GradientLabelOffset x) = "gradientLabelOffset" .= x+legendConfigProperty (GradientStrokeColor s) = "gradientStrokeColor" .= s+legendConfigProperty (GradientStrokeWidth x) = "gradientStrokeWidth" .= x+legendConfigProperty (GradientHeight x) = "gradientHeight" .= x+legendConfigProperty (GradientWidth x) = "gradientWidth" .= x+legendConfigProperty (LeLabelAlign ha) = "labelAlign" .= hAlignLabel ha+legendConfigProperty (LeLabelBaseline va) = "labelBaseline" .= vAlignLabel va+legendConfigProperty (LeLabelColor s) = "labelColor" .= s+legendConfigProperty (LeLabelFont s) = "labelFont" .= s+legendConfigProperty (LeLabelFontSize x) = "labelFontSize" .= x+legendConfigProperty (LeLabelLimit x) = "labelLimit" .= x+legendConfigProperty (LeLabelOffset x) = "labelOffset" .= x+legendConfigProperty (LeShortTimeLabels b) = "shortTimeLabels" .= b+legendConfigProperty (EntryPadding x) = "entryPadding" .= x+legendConfigProperty (SymbolColor s) = "symbolColor" .= s+legendConfigProperty (SymbolType s) = "symbolType" .= symbolLabel s+legendConfigProperty (SymbolSize x) = "symbolSize" .= x+legendConfigProperty (SymbolStrokeWidth x) = "symbolStrokeWidth" .= x+legendConfigProperty (LeTitleAlign ha) = "titleAlign" .= hAlignLabel ha+legendConfigProperty (LeTitleBaseline va) = "titleBaseline" .= vAlignLabel va+legendConfigProperty (LeTitleColor s) = "titleColor" .= s+legendConfigProperty (LeTitleFont s) = "titleFont" .= s+legendConfigProperty (LeTitleFontSize x) = "titleFontSize" .= x+legendConfigProperty (LeTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw+legendConfigProperty (LeTitleLimit x) = "titleLimit" .= x+legendConfigProperty (LeTitlePadding x) = "titlePadding" .= x+++{-|++Indicates the legend orientation. See the+<https://vega.github.io/vega-lite/docs/legend.html#config Vega-Lite documentation>+for more details.+-}++data LegendOrientation+    = BottomLeft+    | BottomRight+    | Left+    | None+    | Right+    | TopLeft+    | TopRight+++legendOrientLabel :: LegendOrientation -> T.Text+legendOrientLabel Left = "left"+legendOrientLabel BottomLeft = "bottom-left"+legendOrientLabel BottomRight = "bottom-right"+legendOrientLabel Right = "right"+legendOrientLabel TopLeft = "top-left"+legendOrientLabel TopRight = "top-right"+legendOrientLabel None = "none"+++{-|++Legend properties. For more detail see the+<https://vega.github.io/vega-lite/docs/legend.html#legend-properties Vega-Lite documentation>.+-}+data LegendProperty+    = LEntryPadding Double+    | LFormat T.Text+    | LOffset Double+    | LOrient LegendOrientation+    | LPadding Double+    | LTickCount Double+    | LTitle T.Text+    | LType Legend+    | LValues LegendValues+    | LZIndex Int+++legendProperty :: LegendProperty -> LabelledSpec+legendProperty (LType lType) = "type" .= legendLabel lType+legendProperty (LEntryPadding x) = "entryPadding" .= x+legendProperty (LFormat s) = "format" .= s+legendProperty (LOffset x) = "offset" .= x+legendProperty (LOrient orl) = "orient" .= legendOrientLabel orl+legendProperty (LPadding x) = "padding" .= x+legendProperty (LTickCount x) = "tickCount" .= x+legendProperty (LTitle ttl) = "title" .= if T.null ttl then A.Null else fromT ttl+legendProperty (LValues vals) =+  let ls = case vals of+        LNumbers xs    -> map toJSON xs+        LDateTimes dts -> map (object . map dateTimeProperty) dts+        LStrings ss    -> map toJSON ss+  in "values" .= ls+legendProperty (LZIndex n) = "zindex" .= n+++-- | A list of data values suitable for setting legend values.++data LegendValues+    = LDateTimes [[DateTime]]+    | LNumbers [Double]+    | LStrings [T.Text]+++-- | Specify the padding dimensions in pixel units.++data Padding+    = PSize Double+      -- ^ Use the same padding on all four edges of the container.+    | PEdges Double Double Double Double+      -- ^ Specify the padding for the left, top, right, and bottom edges.+      +      +paddingSpec :: Padding -> VLSpec+paddingSpec (PSize p) = toJSON p+paddingSpec (PEdges l t r b) =+  object [ "left" .= l+         , "top" .= t+         , "right" .= r+         , "bottom" .= b+         ]++{-|++Types of geographic map projection. These are based on a subset of those provided+by the <https://github.com/d3/d3-geo d3-geo library>. For details of available+projections see the+<https://vega.github.io/vega-lite/docs/projection.html#projection-types Vega-Lite documentation>.+-}+data Projection+    = Albers+    | AlbersUsa+    | AzimuthalEqualArea+    | AzimuthalEquidistant+    | ConicConformal+    | ConicEqualArea+    | ConicEquidistant+    | Custom T.Text+      -- ^ Specify the name of the custom D3 prohection to use. See the+      --   <https://vega.github.io/vega/docs/projections/#register Vega API>+      --   for more information.+    | Equirectangular+    | Gnomonic+    | Mercator+    | Orthographic+    | Stereographic+    | TransverseMercator+++projectionLabel :: Projection -> T.Text+projectionLabel Albers = "albers"+projectionLabel AlbersUsa = "albersUsa"+projectionLabel AzimuthalEqualArea = "azimuthalEqualArea"+projectionLabel AzimuthalEquidistant = "azimuthalEquidistant"+projectionLabel ConicConformal = "conicConformal"+projectionLabel ConicEqualArea = "conicEqualarea"+projectionLabel ConicEquidistant = "conicEquidistant"+projectionLabel (Custom pName) = pName+projectionLabel Equirectangular = "equirectangular"+projectionLabel Gnomonic = "gnomonic"+projectionLabel Mercator = "mercator"+projectionLabel Orthographic = "orthographic"+projectionLabel Stereographic = "stereographic"+projectionLabel TransverseMercator = "transverseMercator"+++-- | Specifies a clipping rectangle in pixel units for defining+--   the clip extent of a map projection.++data ClipRect+    = NoClip+    | LTRB Double Double Double Double+      -- ^ The left, top, right, and bottom extents.+++{-|++Properties for customising a geospatial projection that converts longitude,latitude+pairs into planar (x,y) coordinate pairs for rendering and query. For details see the+<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.+-}+data ProjectionProperty+    = PType Projection+    | PClipAngle (Maybe Double)+    | PClipExtent ClipRect+    | PCenter Double Double+    | PRotate Double Double Double+    | PPrecision Double+    | PCoefficient Double+    | PDistance Double+    | PFraction Double+    | PLobes Int+    | PParallel Double+    | PRadius Double+    | PRatio Double+    | PSpacing Double+    | PTilt Double+++projectionProperty :: ProjectionProperty -> LabelledSpec+projectionProperty (PType proj) = "type" .= projectionLabel proj+projectionProperty (PClipAngle numOrNull) = "clipAngle" .= maybe A.Null toJSON numOrNull+projectionProperty (PClipExtent rClip) =+  ("clipExtent", case rClip of+    NoClip -> A.Null+    LTRB l t r b -> toJSON (map toJSON [l, t, r, b])+  )+projectionProperty (PCenter lon lat) = "center" .= map toJSON [lon, lat]+projectionProperty (PRotate lambda phi gamma) = "rotate" .= map toJSON [lambda, phi, gamma]+projectionProperty (PPrecision pr) = "precision" .= pr+projectionProperty (PCoefficient x) = "coefficient" .= x+projectionProperty (PDistance x) = "distance" .= x+projectionProperty (PFraction x) = "fraction" .= x+projectionProperty (PLobes n) = "lobes" .= n+projectionProperty (PParallel x) = "parallel" .= x+projectionProperty (PRadius x) = "radius" .= x+projectionProperty (PRatio x) = "ratio" .= x+projectionProperty (PSpacing x) = "spacing" .= x+projectionProperty (PTilt x) = "tilt" .= x+++{-|++Sets the cartographic projection used for geospatial coordinates. A projection+defines the mapping from @(longitude,latitude)@ to an @(x,y)@ plane used for rendering.+This is useful when using the 'Geoshape' mark. For further details see the+<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.++@+proj = projection [ PType Orthographic, PRotate (-40) 0 0 ]+@+-}+projection :: [ProjectionProperty] -> (VLProperty, VLSpec)+projection pProps = (VLProjection, object (map projectionProperty pProps))+++{-|++Properties for customising the colors of a range. The parameter should be a+named color scheme such as @\"accent\"@ or @\"purpleorange-11\"@. For details see the+<https://vega.github.io/vega/docs/schemes/#scheme-properties Vega-Lite documentation>.+-}+data RangeConfig+    = RCategory T.Text+    | RDiverging T.Text+    | RHeatmap T.Text+    | ROrdinal T.Text+    | RRamp T.Text+    | RSymbol T.Text+++rangeConfigProperty :: RangeConfig -> LabelledSpec+rangeConfigProperty rangeCfg =+  let (l, n) = case rangeCfg of+        RCategory nme -> ("category", nme)+        RDiverging nme -> ("diverging", nme)+        RHeatmap nme -> ("heatmap", nme)+        ROrdinal nme -> ("ordinal", nme)+        RRamp nme -> ("ramp", nme)+        RSymbol nme -> ("symbol", nme)+            +  in l .= object [schemeProperty n []]+++{-|++Scale configuration property. These are used to configure all scales.+For more details see the+<https://vega.github.io/vega-lite/docs/scale.html#scale-config Vega-Lite documentation>.+-}+data ScaleConfig+    = SCBandPaddingInner Double+    | SCBandPaddingOuter Double+    | SCClamp Bool+    | SCMaxBandSize Double+    | SCMinBandSize Double+    | SCMaxFontSize Double+    | SCMinFontSize Double+    | SCMaxOpacity Double+    | SCMinOpacity Double+    | SCMaxSize Double+    | SCMinSize Double+    | SCMaxStrokeWidth Double+    | SCMinStrokeWidth Double+    | SCPointPadding Double+    | SCRangeStep (Maybe Double)+    | SCRound Bool+    | SCTextXRangeStep Double+    | SCUseUnaggregatedDomain Bool+++scaleConfigProperty :: ScaleConfig -> LabelledSpec+scaleConfigProperty (SCBandPaddingInner x) = "bandPaddingInner" .= x+scaleConfigProperty (SCBandPaddingOuter x) = "bandPaddingOuter" .= x+scaleConfigProperty (SCClamp b) = "clamp" .= b+scaleConfigProperty (SCMaxBandSize x) = "maxBandSize" .= x+scaleConfigProperty (SCMinBandSize x) = "minBandSize" .= x+scaleConfigProperty (SCMaxFontSize x) = "maxFontSize" .= x+scaleConfigProperty (SCMinFontSize x) = "minFontSize" .= x+scaleConfigProperty (SCMaxOpacity x) = "maxOpacity" .= x+scaleConfigProperty (SCMinOpacity x) = "minOpacity" .= x+scaleConfigProperty (SCMaxSize x) = "maxSize" .= x+scaleConfigProperty (SCMinSize x) = "minSize" .= x+scaleConfigProperty (SCMaxStrokeWidth x) = "maxStrokeWidth" .= x+scaleConfigProperty (SCMinStrokeWidth x) = "minStrokeWidth" .= x+scaleConfigProperty (SCPointPadding x) = "pointPadding" .= x+scaleConfigProperty (SCRangeStep numOrNull) = "rangeStep" .= maybe A.Null toJSON numOrNull+scaleConfigProperty (SCRound b) = "round" .= b+scaleConfigProperty (SCTextXRangeStep x) = "textXRangeStep" .= x+scaleConfigProperty (SCUseUnaggregatedDomain b) = "useUnaggregatedDomain" .= b+++-- | Indicates the type of selection to be generated by the user.++data Selection+    = Single+      -- ^ Allows one mark at a time to be selected.+    | Multi+      -- ^ Allows multiple items to be selected (e.g. with+      --   shift-click).+    | Interval+      -- ^ Allows a bounding rectangle to be dragged by the user,+      --   selecting all items which intersect it.+++selectionLabel :: Selection -> T.Text+selectionLabel Single = "single"+selectionLabel Multi = "multi"+selectionLabel Interval = "interval"+++{-|++Properties for customising the nature of the selection. See the+<https://vega.github.io/vega-lite/docs/selection.html#selection-properties Vega-Lite documentation>+for details.+-}+data SelectionProperty+    = On T.Text+      -- ^ A <https://vega.github.io/vega/docs/event-streams Vega event stream>+      --   or the empty string (which sets the property to @false@).+    | Translate T.Text+      -- ^ A <https://vega.github.io/vega/docs/event-streams Vega event stream>+      --   or the empty string (which sets the property to @false@).+    | Zoom T.Text+      -- ^ A <https://vega.github.io/vega/docs/event-streams Vega event stream>+      --   or the empty string (which sets the property to @false@).+    | Fields [T.Text]+    | Encodings [Channel]+    | Empty+    | ResolveSelections SelectionResolution+    | SelectionMark [SelectionMarkProperty]+    | BindScales+    | Bind [Binding]+    | Nearest Bool+    | Toggle T.Text+      -- ^ A <https://vega.github.io/vega/docs/expressions Vega expression> that evaluates+      --   to @true@ or @false@.++      +selectionProperty :: SelectionProperty -> LabelledSpec+selectionProperty (Fields fNames) = "fields" .= map toJSON fNames+selectionProperty (Encodings channels) = "encodings" .= map (toJSON . channelLabel) channels+selectionProperty (On e) = "on" .= e+selectionProperty Empty = "empty" .= ("none" :: T.Text)+selectionProperty (ResolveSelections res) = "resolve" .= selectionResolutionLabel res+selectionProperty (SelectionMark markProps) = "mark" .= object (map selectionMarkProperty markProps)+selectionProperty BindScales = "bind" .= ("scales" :: T.Text)+selectionProperty (Bind binds) = "bind" .= object (map bindingSpec binds)+selectionProperty (Nearest b) = "nearest" .= b+selectionProperty (Toggle expr) = "toggle" .= expr+selectionProperty (Translate e) = "translate" .= if T.null e then toJSON False else toJSON e+selectionProperty (Zoom e) = "zoom" .= if T.null e then toJSON False else toJSON e+++-- | Indicates a channel type to be used in a resolution specification.++data Channel+    = ChX+    | ChY+    | ChX2+    | ChY2+    | ChColor+    | ChOpacity+    | ChShape+    | ChSize+++channelLabel :: Channel -> T.Text+channelLabel ChX = "x"+channelLabel ChY = "y"+channelLabel ChX2 = "x2"+channelLabel ChY2 = "y2"+channelLabel ChColor = "color"+channelLabel ChOpacity = "opacity"+channelLabel ChShape = "shape"+channelLabel ChSize = "size"+++{-|++Determines how selections in faceted or repeated views are resolved. See the+<https://vega.github.io/vega-lite/docs/selection.html#resolve Vega-Lite documentation>+for details+-}+data SelectionResolution+    = Global+    | Union+    | Intersection+++selectionResolutionLabel :: SelectionResolution -> T.Text+selectionResolutionLabel Global = "global"+selectionResolutionLabel Union = "union"+selectionResolutionLabel Intersection = "intersect"+++{-|++Properties for customising the appearance of an interval selection mark (dragged+rectangle). For details see the+<https://vega.github.io/vega-lite/docs/selection.html#interval-mark Vega-Lite documentation>.+-}+data SelectionMarkProperty+    = SMFill T.Text+    | SMFillOpacity Double+    | SMStroke T.Text+    | SMStrokeOpacity Double+    | SMStrokeWidth Double+    | SMStrokeDash [Double]+    | SMStrokeDashOffset Double+++selectionMarkProperty :: SelectionMarkProperty -> LabelledSpec+selectionMarkProperty (SMFill colour) = "fill" .= colour+selectionMarkProperty (SMFillOpacity x) = "fillOpacity" .= x+selectionMarkProperty (SMStroke colour) = "stroke" .= colour+selectionMarkProperty (SMStrokeOpacity x) = "strokeOpacity" .= x+selectionMarkProperty (SMStrokeWidth x) = "strokeWidth" .= x+selectionMarkProperty (SMStrokeDash xs) = "strokeDash" .= map toJSON xs+selectionMarkProperty (SMStrokeDashOffset x) = "strokeDashOffset" .= x+++{-|++GUI Input properties. The type of relevant property will depend on the type of+input element selected. For example an @InRange@ (slider) can have numeric min,+max and step values; @InSelect@ (selector) has a list of selection label options.+For details see the+<https://vega.github.io/vega/docs/signals/#bind Vega input element binding documentation>.++The @debounce@ property, available for all input types allows a delay in input event+handling to be added in order to avoid unnecessary event broadcasting. The @Element@+property is an optional CSS selector indicating the parent element to which the+input element should be added. This allows the option of the input element to be+outside the visualization container.+-}+data InputProperty+    = Debounce Double+    | Element T.Text+    | InOptions [T.Text]+    | InMin Double+    | InMax Double+    | InName T.Text+    | InStep Double+    | InPlaceholder T.Text+++inputProperty :: InputProperty -> LabelledSpec+inputProperty (InMin x) = "min".= x+inputProperty (InMax x) = "max".= x+inputProperty (InStep x) = "step".= x+inputProperty (Debounce x) = "debounce".= x+inputProperty (InName s) = "name" .= s+inputProperty (InOptions opts) = "options" .= map toJSON opts+inputProperty (InPlaceholder el) = "placeholder" .= toJSON el+inputProperty (Element el) = "element" .= toJSON el+++{-|++Describes the binding property of a selection based on some HTML input element+such as a checkbox or radio button. For details see the+<https://vega.github.io/vega-lite/docs/bind.html#scale-binding Vega-Lite documentation>+and the+<https://vega.github.io/vega/docs/signals/#bind Vega input binding documentation>.+-}+data Binding+    = IRange T.Text [InputProperty]+    | ICheckbox T.Text [InputProperty]+    | IRadio T.Text [InputProperty]+    | ISelect T.Text [InputProperty]+      -- TODO: Check validity: The following input types can generate a warning if options are included even if options appear to have an effect (e.g. placeholder)+    | IText T.Text [InputProperty]+    | INumber T.Text [InputProperty]+    | IDate T.Text [InputProperty]+    | ITime T.Text [InputProperty]+    | IMonth T.Text [InputProperty]+    | IWeek T.Text [InputProperty]+    | IDateTimeLocal T.Text [InputProperty]+    | ITel T.Text [InputProperty]+    | IColor T.Text [InputProperty]+++bindingSpec :: Binding -> LabelledSpec+bindingSpec bnd =+  let (lbl, input, ps) = case bnd of+        IRange label props -> (label, "range" :: T.Text, props)+        ICheckbox label props -> (label, "checkbox", props)+        IRadio label props -> (label, "radio", props)+        ISelect label props -> (label, "select", props)+        IText label props -> (label, "text", props)+        INumber label props -> (label, "number", props)+        IDate label props -> (label, "date", props)+        ITime label props -> (label, "time", props)+        IMonth label props -> (label, "month", props)+        IWeek label props -> (label, "week", props)+        IDateTimeLocal label props -> (label, "datetimelocal", props)+        ITel label props -> (label, "tel", props)+        IColor label props -> (label, "color", props)++  in (lbl, object (("input" .= input) : map inputProperty ps))+++-- | Indicates the anchor position for text.++data APosition+    = AStart+    | AMiddle+    | AEnd+++anchorLabel :: APosition -> T.Text+anchorLabel AStart = "start"+anchorLabel AMiddle = "middle"+anchorLabel AEnd = "end"+++{-|++Title configuration properties. These are used to configure the default style+of all titles within a visualization.+For further details see the+<https://vega.github.io/vega-lite/docs/title.html#config Vega-Lite documentation>.+-}+data TitleConfig+    = TAnchor APosition+    | TAngle Double+    | TBaseline VAlign+    | TColor T.Text+    | TFont T.Text+    | TFontSize Double+    | TFontWeight FontWeight+    | TLimit Double+    | TOffset Double+    | TOrient Side+++titleConfigSpec :: TitleConfig -> LabelledSpec+titleConfigSpec (TAnchor an) = "anchor" .= anchorLabel an+titleConfigSpec (TAngle x) = "angle" .= x+titleConfigSpec (TBaseline va) = "baseline" .= vAlignLabel va+titleConfigSpec (TColor clr) = "color" .= clr+titleConfigSpec (TFont fnt) = "font" .= fnt+titleConfigSpec (TFontSize x) = "fontSize" .= x+titleConfigSpec (TFontWeight w) = "fontWeight" .= fontWeightSpec w+titleConfigSpec (TLimit x) = "limit" .= x+titleConfigSpec (TOffset x) = "offset" .= x+titleConfigSpec (TOrient sd) = "orient" .= sideLabel sd+++{-|++View configuration property. These are used to configure the style of a single+view within a visualization such as its size and default fill and stroke colors.+For further details see the+<https://vega.github.io/vega-lite/docs/spec.html#config Vega-Lite documentation>.+-}+data ViewConfig+    = ViewWidth Double+    | ViewHeight Double+    | Clip Bool+    | Fill (Maybe T.Text)+    | FillOpacity Double+    | Stroke (Maybe T.Text)+    | StrokeOpacity Double+    | StrokeWidth Double+    | StrokeDash [Double]+    | StrokeDashOffset Double+++viewConfigProperty :: ViewConfig -> LabelledSpec+viewConfigProperty (ViewWidth x) = "width" .= x+viewConfigProperty (ViewHeight x) = "height" .= x+viewConfigProperty (Clip b) = "clip" .= b+viewConfigProperty (Fill ms) = "fill" .= fromMaybe "" ms+viewConfigProperty (FillOpacity x) = "fillOpacity" .= x+viewConfigProperty (Stroke ms) = "stroke" .= fromMaybe "" ms+viewConfigProperty (StrokeOpacity x) = "strokeOpacity" .= x+viewConfigProperty (StrokeWidth x) = "strokeWidth" .= x+viewConfigProperty (StrokeDash xs) = "strokeDash" .= map toJSON xs+viewConfigProperty (StrokeDashOffset x) = "strokeDashOffset" .= x+++{-|+Type of configuration property to customise. See the+<https://vega.github.io/vega-lite/docs/config.html Vega-Lite documentation>+for details.+-}+data ConfigurationProperty+    = AreaStyle [MarkProperty]+    | Autosize [Autosize]+    | Axis [AxisConfig]+    | AxisX [AxisConfig]+    | AxisY [AxisConfig]+    | AxisLeft [AxisConfig]+    | AxisRight [AxisConfig]+    | AxisTop [AxisConfig]+    | AxisBottom [AxisConfig]+    | AxisBand [AxisConfig]+    | Background T.Text+    | BarStyle [MarkProperty]+    | CircleStyle [MarkProperty]+    | CountTitle T.Text+    | FieldTitle FieldTitleProperty+    | Legend [LegendConfig]+    | LineStyle [MarkProperty]+    | MarkStyle [MarkProperty]+    | NamedStyle T.Text [MarkProperty]+    | NumberFormat T.Text+    | Padding Padding+    | PointStyle [MarkProperty]+    | Projection [ProjectionProperty]+    | Range [RangeConfig]+    | RectStyle [MarkProperty]+    | RemoveInvalid Bool+    | RuleStyle [MarkProperty]+    | Scale [ScaleConfig]+    | SelectionStyle [(Selection, [SelectionProperty])]+    | SquareStyle [MarkProperty]+    | Stack StackProperty+    | TextStyle [MarkProperty]+    | TickStyle [MarkProperty]+    | TitleStyle [TitleConfig]+    | TimeFormat T.Text+    | View [ViewConfig]+++configProperty :: ConfigurationProperty -> LabelledSpec+configProperty (Autosize aus) = "autosize" .= object (map autosizeProperty aus)+configProperty (Background bg) = "background" .= bg+configProperty (CountTitle ttl) = "countTitle" .= ttl+configProperty (FieldTitle ftp) = "fieldTitle" .= fieldTitleLabel ftp+configProperty (RemoveInvalid b) = "invalidValues" .= if b then "filter" else A.Null+configProperty (NumberFormat fmt) = "numberFormat" .= fmt+configProperty (Padding pad) = "padding" .= paddingSpec pad+configProperty (TimeFormat fmt) = "timeFormat" .= fmt+configProperty (Axis acs) = "axis" .= object (map axisConfigProperty acs)+configProperty (AxisX acs) = "axisX" .= object (map axisConfigProperty acs)+configProperty (AxisY acs) = "axisY" .= object (map axisConfigProperty acs)+configProperty (AxisLeft acs) = "axisLeft" .= object (map axisConfigProperty acs)+configProperty (AxisRight acs) = "axisRight" .= object (map axisConfigProperty acs)+configProperty (AxisTop acs) = "axisTop" .= object (map axisConfigProperty acs)+configProperty (AxisBottom acs) = "axisBottom" .= object (map axisConfigProperty acs)+configProperty (AxisBand acs) = "axisBand" .= object (map axisConfigProperty acs)+configProperty (Legend lcs) = "legend" .= object (map legendConfigProperty lcs)+configProperty (MarkStyle mps) = "mark" .= object (map markProperty mps)+configProperty (Projection pps) = "projection" .= object (map projectionProperty pps)+configProperty (AreaStyle mps) = "area" .= object (map markProperty mps)+configProperty (BarStyle mps) = "bar" .= object (map markProperty mps)+configProperty (CircleStyle mps) = "circle" .= object (map markProperty mps)+configProperty (LineStyle mps) = "line" .= object (map markProperty mps)+configProperty (PointStyle mps) = "point" .= object (map markProperty mps)+configProperty (RectStyle mps) = "rect" .= object (map markProperty mps)+configProperty (RuleStyle mps) = "rule" .= object (map markProperty mps)+configProperty (SquareStyle mps) = "square" .= object (map markProperty mps)+configProperty (TextStyle mps) = "text" .= object (map markProperty mps)+configProperty (TickStyle mps) = "tick" .= object (map markProperty mps)+configProperty (TitleStyle tcs) = "title" .= object (map titleConfigSpec tcs)+configProperty (NamedStyle nme mps) = "style" .= object [nme .= object (map markProperty mps)]+configProperty (Scale scs) = "scale" .= object (map scaleConfigProperty scs)+configProperty (Stack sp) = stackProperty sp+configProperty (Range rcs) = "range" .= object (map rangeConfigProperty rcs)+configProperty (SelectionStyle selConfig) = +  let selProp (sel, sps) = selectionLabel sel .= object (map selectionProperty sps)+  in "selection" .= object (map selProp selConfig)+configProperty (View vcs) = "view" .= object (map viewConfigProperty vcs)+++{-|++Axis configuration options for customising all axes. See the+<https://vega.github.io/vega-lite/docs/axis.html#general-config Vega-Lite documentation>+for more details.+-}+data AxisConfig+    = BandPosition Double+    | Domain Bool+    | DomainColor T.Text+    | DomainWidth Double+    | MaxExtent Double+    | MinExtent Double+    | Grid Bool+    | GridColor T.Text+    | GridDash [Double]+    | GridOpacity Double+    | GridWidth Double+    | Labels Bool+    | LabelAngle Double+    | LabelColor T.Text+    | LabelFont T.Text+    | LabelFontSize Double+    | LabelLimit Double+    | LabelOverlap OverlapStrategy+    | LabelPadding Double+    | ShortTimeLabels Bool+    | Ticks Bool+    | TickColor T.Text+    | TickRound Bool+    | TickSize Double+    | TickWidth Double+    | TitleAlign HAlign+    | TitleAngle Double+    | TitleBaseline VAlign+    | TitleColor T.Text+    | TitleFont T.Text+    | TitleFontWeight FontWeight+    | TitleFontSize Double+    | TitleLimit Double+    | TitleMaxLength Double+    | TitlePadding Double+    | TitleX Double+    | TitleY Double+++axisConfigProperty :: AxisConfig -> LabelledSpec+axisConfigProperty (BandPosition x) = ("bandPosition", toJSON x)+axisConfigProperty (Domain b) = ("domain", toJSON b)+axisConfigProperty (DomainColor c) = ("domainColor", fromT c)+axisConfigProperty (DomainWidth w) = ("domainWidth", toJSON w)+axisConfigProperty (MaxExtent n) = ("maxExtent", toJSON n)+axisConfigProperty (MinExtent n) = ("minExtent", toJSON n)+axisConfigProperty (Grid b) = ("grid", toJSON b)+axisConfigProperty (GridColor c) = ("gridColor", fromT c)+axisConfigProperty (GridDash ds) = ("gridDash", toJSON (map toJSON ds))+axisConfigProperty (GridOpacity o) = ("gridOpacity", toJSON o)+axisConfigProperty (GridWidth x) = ("gridWidth", toJSON x)+axisConfigProperty (Labels b) = ("labels", toJSON b)+axisConfigProperty (LabelAngle angle) = ("labelAngle", toJSON angle)+axisConfigProperty (LabelColor c) = ("labelColor", fromT c)+axisConfigProperty (LabelFont f) = ("labelFont", fromT f)+axisConfigProperty (LabelFontSize x) = ("labelFontSize", toJSON x)+axisConfigProperty (LabelLimit x) = ("labelLimit", toJSON x)+axisConfigProperty (LabelOverlap strat) = ("labelOverlap", fromT (overlapStrategyLabel strat))+axisConfigProperty (LabelPadding pad) = ("labelPadding", toJSON pad)+axisConfigProperty (ShortTimeLabels b) = ("shortTimeLabels", toJSON b)+axisConfigProperty (Ticks b) = ("ticks", toJSON b)+axisConfigProperty (TickColor c) = ("tickColor", fromT c)+axisConfigProperty (TickRound b) = ("tickRound", toJSON b)+axisConfigProperty (TickSize x) = ("tickSize", toJSON x)+axisConfigProperty (TickWidth x) = ("tickWidth", toJSON x)+axisConfigProperty (TitleAlign align) = ("titleAlign", fromT (hAlignLabel align))+axisConfigProperty (TitleAngle angle) = ("titleAngle", toJSON angle)+axisConfigProperty (TitleBaseline va) = ("titleBaseline", fromT (vAlignLabel va))+axisConfigProperty (TitleColor c) = ("titleColor", fromT c)+axisConfigProperty (TitleFont f) = ("titleFont", fromT f)+axisConfigProperty (TitleFontWeight w) = ("titleFontWeight", fontWeightSpec w)+axisConfigProperty (TitleFontSize x) = ("titleFontSize", toJSON x)+axisConfigProperty (TitleLimit x) = ("titleLimit", toJSON x)+axisConfigProperty (TitleMaxLength x) = ("titleMaxLength", toJSON x)+axisConfigProperty (TitlePadding x) = ("titlePadding", toJSON x)+axisConfigProperty (TitleX x) = ("titleX", toJSON x)+axisConfigProperty (TitleY y) = ("titleY", toJSON y)+++{-|++Used for creating logical compositions. For example++@+color+    [ MSelectionCondition (Or (SelectionName "alex") (SelectionName "morgan"))+        [ MAggregate Count, MName "*", MmType Quantitative ]+        [ MString "gray" ]+    ]+@++Logical compositions can be nested to any level as shown in this example++@+Not (And (Expr "datum.IMDB_Rating === null") (Expr "datum.Rotten_Tomatoes_Rating === null") )+@+-}+data BooleanOp+    = Expr T.Text+    | Selection T.Text+    | SelectionName T.Text+    | And BooleanOp BooleanOp+    | Or BooleanOp BooleanOp+    | Not BooleanOp+++booleanOpSpec :: BooleanOp -> VLSpec+booleanOpSpec (Expr expr) = toJSON expr+booleanOpSpec (SelectionName selName) = toJSON selName+booleanOpSpec (Selection sel) = object ["selection" .= sel]+booleanOpSpec (And operand1 operand2) = object ["and" .= [booleanOpSpec operand1, booleanOpSpec operand2]]+booleanOpSpec (Or operand1 operand2) = object ["or" .= [booleanOpSpec operand1, booleanOpSpec operand2]]+booleanOpSpec (Not operand) = object ["not" .= booleanOpSpec operand]+++{-|++Type of filtering operation. See the+<https://vega.github.io/vega-lite/docs/filter.html Vega-Lite documentation>+for details.+-}+data Filter+    = FEqual T.Text DataValue+    | FExpr T.Text+    | FCompose BooleanOp+    | FSelection T.Text+    | FOneOf T.Text DataValues+    | FRange T.Text FilterRange+++{-|++A pair of filter range data values. The first argument is the inclusive minimum+vale to accept and the second the inclusive maximum.+-}+data FilterRange+    = NumberRange Double Double+    | DateRange [DateTime] [DateTime]+++{-|++Specifies the type and content of geometry specifications for programatically+creating GeoShapes. These can be mapped to the+<https://tools.ietf.org/html/rfc7946#section-3.1 GeoJson geometry object types>+where the pluralised type names refer to their @Multi@ prefixed equivalent in the+GeoJSON specification.+-}+data Geometry+    = GeoPoint Double Double+    | GeoPoints [(Double, Double)]+    | GeoLine [(Double, Double)]+    | GeoLines [[(Double, Double)]]+    | GeoPolygon [[(Double, Double)]]+    | GeoPolygons [[[(Double, Double)]]]+++{-|++Specifies a geometric object to be used in a geoShape specification. The first+parameter is the geometric type, the second an optional list of properties to be+associated with the object.++@+geojson =+    geometry (GeoPolygon [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []+@+-}+geometry :: Geometry -> [(T.Text, DataValue)] -> VLSpec+geometry gType properties =+  object ([ ("type", fromT "Feature")+          , ("geometry", geometryTypeSpec gType) ]+          <> if null properties+             then []+             else [("properties",+                    object (map (second dataValueSpec) properties))]+         )+++geometryTypeSpec :: Geometry -> VLSpec+geometryTypeSpec gType =+  let toCoords :: [(Double, Double)] -> VLSpec+      toCoords = toJSON -- rely on Aeson converting a pair to a 2-element list++      toCoordList :: [[(Double, Double)]] -> VLSpec+      toCoordList = toJSON . map toCoords  -- this is just toJSON isn't it?++      -- can we replace this infinite tower of toJSON calls with one toJSON call?+      (ptype, cs) = case gType of+        GeoPoint x y -> ("Point", toJSON [x, y])+        GeoPoints coords -> ("MultiPoint", toCoords coords)+        GeoLine coords -> ("LineString", toCoords coords)+        GeoLines coords -> ("MultiLineString", toCoordList coords)+        GeoPolygon coords -> ("Polygon", toCoordList coords)+        GeoPolygons ccoords -> ("MultiPolygon", toJSON (map toCoordList ccoords))++  in object [("type", ptype), ("coordinates", cs)]+++{-|++Indicates whether or not a scale domain should be independent of others in a+composite visualization. See the+<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation> for+details.+-}+data Resolution+    = Shared+    | Independent+++resolutionLabel :: Resolution -> T.Text+resolutionLabel Shared = "shared"+resolutionLabel Independent = "independent"+++{-|++Used to determine how a channel's axis, scale or legend domains should be resolved+if defined in more than one view in a composite visualization. See the+<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation>+for details.+-}+data Resolve+    = RAxis [(Channel, Resolution)]+    | RLegend [(Channel, Resolution)]+    | RScale [(Channel, Resolution)]+++resolveProperty :: Resolve -> LabelledSpec+resolveProperty res =+  let (nme, rls) = case res of+        RAxis chRules -> ("axis", chRules)+        RLegend chRules -> ("legend", chRules)+        RScale chRules -> ("scale", chRules)++      ans = map (\(ch, rule) -> (channelLabel ch .= resolutionLabel rule)) rls+  in (nme, object ans)+++{-|++Represents a facet header property. For details, see the+<https://vega.github.io/vega-lite/docs/facet.html#header Vega-Lite documentation>.+-}+data HeaderProperty+    = HFormat T.Text+    | HTitle T.Text+++headerProperty :: HeaderProperty -> LabelledSpec+headerProperty (HFormat fmt) = "format" .= fmt+headerProperty (HTitle ttl) = "title" .= ttl+++-- | Types of hyperlink channel property used for linking marks or text to URLs.++data HyperlinkChannel+    = HName T.Text+    | HRepeat Arrangement+    | HmType Measurement+    | HBin [BinProperty]+    | HAggregate Operation+    | HTimeUnit TimeUnit+    | HSelectionCondition BooleanOp [HyperlinkChannel] [HyperlinkChannel]+    | HDataCondition BooleanOp [HyperlinkChannel] [HyperlinkChannel]+    | HString T.Text+++hyperlinkChannelProperty :: HyperlinkChannel -> [LabelledSpec]+hyperlinkChannelProperty (HName s) = [field_ s]+hyperlinkChannelProperty (HRepeat arr) = ["field" .= object [repeat_ arr]]+hyperlinkChannelProperty (HmType t) = [type_ t]+hyperlinkChannelProperty (HBin bps) = [bin bps]+hyperlinkChannelProperty (HSelectionCondition selName ifClause elseClause) =+  let h = ("condition", hkey)+      toProps = concatMap hyperlinkChannelProperty+      hkey = object (("selection", booleanOpSpec selName) : toProps ifClause)+      hs = toProps elseClause+  in h : hs+hyperlinkChannelProperty (HDataCondition predicate ifClause elseClause) =+  let h = ("condition", hkey)+      toProps = concatMap hyperlinkChannelProperty+      hkey = object (("test", booleanOpSpec predicate) : toProps ifClause)+      hs = toProps elseClause+  in h : hs+hyperlinkChannelProperty (HTimeUnit tu) = [timeUnit_ tu]+hyperlinkChannelProperty (HAggregate op) = [aggregate_ op]+hyperlinkChannelProperty (HString s) = [value_ s]++----++{-|++Create a pair of continuous domain to color mappings suitable for customising+ordered scales. The first parameter is a tuple representing the mapping of the lowest+numeric value in the domain to its equivalent color; the second tuple the mapping+of the highest numeric value to color. If the domain contains any values between+these lower and upper bounds they are interpolated according to the scale's interpolation+function. This is a convenience function equivalent to specifying separate 'SDomain'+and 'SRange' lists and is safer as it guarantees a one-to-one correspondence between+domain and range values.++@+color+    [ MName "year"+    , MmType Ordinal+    , MScale (domainRangeMap ( 1955, "#e6959c" ) ( 2000, "#911a24" ))+    ]+@+-}++domainRangeMap :: (Double, T.Text) -> (Double, T.Text) -> [ScaleProperty]+domainRangeMap lowerMap upperMap =+  let (domain, range) = unzip [lowerMap, upperMap]+  in [SDomain (DNumbers domain), SRange (RStrings range)]+++{-|++Create a set of discrete domain to color mappings suitable for customising categorical+scales. The first item in each tuple should be a domain value and the second the+color value with which it should be associated. It is a convenience function equivalent+to specifying separate 'SDomain' and 'SRange' lists and is safer as it guarantees+a one-to-one correspondence between domain and range values.++@+color+    [ MName "weather"+    , MmType Nominal+    , MScale (+        categoricalDomainMap+            [ ( "sun", "yellow" )+            , ( "rain", "blue" )+            , ( "fog", "grey" )+            ]+        )+    ]+@+-}++categoricalDomainMap :: [(T.Text, T.Text)] -> [ScaleProperty]+categoricalDomainMap scaleDomainPairs =+  let (domain, range) = unzip scaleDomainPairs+  in [SDomain (DStrings domain), SRange (RStrings range)]+++{-|++Create a list of fields to use in set of repeated small multiples. The list of+fields named here can be referenced in an encoding with @PRepeat Column@+or @PRepeat Row@.+-}+data RepeatFields+    = RowFields [T.Text]+    | ColumnFields [T.Text]+++repeatFieldsProperty :: RepeatFields -> LabelledSpec+repeatFieldsProperty rfs =+  let (nme, vs) = case rfs of+        RowFields fields -> ("row", fields)+        ColumnFields fields -> ("column", fields)++  in nme .= map toJSON vs+++{-|++Types of facet channel property used for creating a composed facet view of small+multiples.+-}+data FacetChannel+    = FName T.Text+    | FmType Measurement+    | FBin [BinProperty]+    | FAggregate Operation+    | FTimeUnit TimeUnit+    | FHeader [HeaderProperty]+++facetChannelProperty :: FacetChannel -> LabelledSpec+facetChannelProperty (FName s) = field_ s+facetChannelProperty (FmType measure) = type_ measure+facetChannelProperty (FBin bps) = bin bps+facetChannelProperty (FAggregate op) = aggregate_ op+facetChannelProperty (FTimeUnit tu) = timeUnit_ tu+facetChannelProperty (FHeader hProps) = "header" .= object (map headerProperty hProps)+++-- | Types of text channel property used for displaying text as part of the visualization.++data TextChannel+    = TName T.Text+    | TRepeat Arrangement+    | TmType Measurement+    | TBin [BinProperty]+    | TAggregate Operation+    | TTimeUnit TimeUnit+    | TSelectionCondition BooleanOp [TextChannel] [TextChannel]+    | TDataCondition BooleanOp [TextChannel] [TextChannel]+    | TFormat T.Text+++textChannelProperty :: TextChannel -> [LabelledSpec]+textChannelProperty (TName s) = [field_  s]+textChannelProperty (TRepeat arr) = ["field" .= object [repeat_ arr]]+textChannelProperty (TmType measure) = [type_ measure]+textChannelProperty (TBin bps) = [bin bps]+textChannelProperty (TAggregate op) = [aggregate_ op]+textChannelProperty (TTimeUnit tu) = [timeUnit_ tu]+textChannelProperty (TFormat fmt) = ["format" .= fmt]+textChannelProperty (TSelectionCondition selName ifClause elseClause) =+  let h = ("condition", hkey)+      toProps = concatMap textChannelProperty+      hkey = object (("selection", booleanOpSpec selName) : toProps ifClause)+      hs = toProps elseClause+  in h : hs+textChannelProperty (TDataCondition predicate ifClause elseClause) =+  let h = ("condition", hkey)+      toProps = concatMap textChannelProperty+      hkey = object (("test", booleanOpSpec predicate) : toProps ifClause)+      hs = toProps elseClause+  in h : hs+++-- | Properties of an ordering channel used for sorting data fields.++data OrderChannel+    = OName T.Text+    | ORepeat Arrangement+    | OmType Measurement+    | OBin [BinProperty]+    | OAggregate Operation+    | OTimeUnit TimeUnit+    | OSort [SortProperty]+++orderChannelProperty :: OrderChannel -> LabelledSpec+orderChannelProperty (OName s) = field_ s+orderChannelProperty (ORepeat arr) = "field" .= object [repeat_ arr]+orderChannelProperty (OmType measure) = type_ measure+orderChannelProperty (OBin bps) = bin bps+orderChannelProperty (OAggregate op) = aggregate_ op+orderChannelProperty (OTimeUnit tu) = timeUnit_ tu+orderChannelProperty (OSort ops) = sort_ ops+++-- | Level of detail channel properties used for creating a grouped channel encoding.++data DetailChannel+    = DName T.Text+    | DmType Measurement+    | DBin [BinProperty]+    | DTimeUnit TimeUnit+    | DAggregate Operation+++detailChannelProperty :: DetailChannel -> LabelledSpec+detailChannelProperty (DName s) = field_ s+detailChannelProperty (DmType t) = type_ t+detailChannelProperty (DBin bps) = bin bps+detailChannelProperty (DTimeUnit tu) = timeUnit_ tu+detailChannelProperty (DAggregate op) = aggregate_ op+++{-|++Provides details of the mapping between a row or column and its field+definitions in a set of faceted small multiples. For details see the+<https://vega.github.io/vega-lite/docs/facet.html#mapping Vega-Lite documentation>.+-}+data FacetMapping+    = ColumnBy [FacetChannel]+    | RowBy [FacetChannel]+++facetMappingProperty :: FacetMapping -> LabelledSpec+facetMappingProperty (RowBy fFields) =+  "row" .= object (map facetChannelProperty fFields)+facetMappingProperty (ColumnBy fFields) =+  "column" .= object (map facetChannelProperty fFields)+++{-|++Create a single global configuration from a list of configuration specifications.+Configurations are applied to all relevant items in the specification. See the+<https://vega.github.io/vega-lite/docs/config.html Vega-Lite documentation> for+more details.++@+config =+    configure+        . configuration (Axis [ DomainWidth 1 ])+        . configuration (View [ Stroke (Just "transparent") ])+        . configuration (SelectionStyle [ ( Single, [ On "dblclick" ] ) ])+@+-}+configure :: [LabelledSpec] -> (VLProperty, VLSpec)+configure configs = (VLConfig, object configs)+++{-|++Defines the fields that will be used to facet a view in rows or columns to create+a set of small multiples. This is used where the encoding of the visualization in small+multiples is identical, but data for each is grouped by the given fields. When+creating a faceted view in this way you also need to define a full specification+to apply to each of those facets using 'asSpec'.++@+toVegaLite+    [ facet [ RowBy [ FName \"Origin\", FmType Nominal ] ]+    , specifcation spec+    ]+@++See the+<https://vega.github.io/vega-lite/docs/facet.html Vega-Lite documentation>+for further details.++-}++facet :: [FacetMapping] -> (VLProperty, VLSpec)+facet fMaps = (VLFacet, object (map facetMappingProperty fMaps))+++{-|++Overrides the default height of the visualization. If not specified the height+will be calculated based on the content of the visualization.++@+toVegaLite+    [ height 300+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+height :: Double -> (VLProperty, VLSpec)+height h = (VLHeight, toJSON h)+++{-|++Assigns a list of specifications to be juxtaposed horizontally in a visualization.++@+toVegaLite+    [ dataFromUrl "data/driving.json" []+    , hConcat [ spec1, spec2 ]+    ]+@+-}+hConcat :: [VLSpec] -> (VLProperty, VLSpec)+hConcat specs = (VLHConcat, toJSON specs)+++{-|++Assigns a list of specifications to superposed layers in a visualization.++@+toVegaLite+    [ dataFromUrl "data/driving.json" []+    , layer [ spec1, spec2 ]+    ]+@+-}+layer :: [VLSpec] -> (VLProperty, VLSpec)+layer specs = (VLLayer, toJSON specs)+++{-|++Provides an optional name to be associated with the visualization.++@+toVegaLite+    [ name \"PopGrowth\"+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+name :: T.Text -> (VLProperty, VLSpec)+name s = (VLName, toJSON s)+++{-|++Set the padding around the visualization in pixel units. The way padding is+interpreted will depend on the 'autosize' properties. See the+<https://vega.github.io/vega-lite/docs/spec.html#top-level-specifications Vega-Lite documentation>+for details.++@+toVegaLite+    [ width 500+    , padding (PEdges 20 10 5 15)+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+padding :: Padding -> (VLProperty, VLSpec)+padding pad = (VLPadding, paddingSpec pad)+++{-|++Define the fields that will be used to compose rows and columns of a set of+small multiples. This is used where the encoding of the visualization in small+multiples is largely identical, but the data field used in each might vary. When+a list of fields is identified with @repeat@ you also need to define a full specification+to apply to each of those fields using 'asSpec'.++@+toVegaLite+    [ repeat [ ColumnFields [ \"Cat\", \"Dog\", \"Fish\" ] ]+    , specification (asSpec spec)+    ]+@++See the+<https://vega.github.io/vega-lite/docs/repeat.html Vega-Lite documentation>+for further details.++-}+repeat :: [RepeatFields] -> (VLProperty, VLSpec)+repeat fields = (VLRepeat, object (map repeatFieldsProperty fields))+++{-|++Determine whether scales, axes or legends in composite views should share channel+encodings. This allows, for example, two different color encodings to be created+in a layered view, which otherwise by default would share color channels between+layers. Each resolution rule should be in a tuple pairing the channel to which it+applies and the rule type.++@+let res = resolve+            . resolution (RLegend [ ( ChColor, Independent ) ])+in toVegaLite+    [ dataFromUrl "data/movies.json" []+    , vConcat [ heatSpec, barSpec ]+    , res []+    ]+@++For more information see the+<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation>.++-}+resolve :: [LabelledSpec] -> (VLProperty, VLSpec)+resolve res = (VLResolve, object res)+++{-|++Create a full selection specification from a list of selections. For details+see the+<https://vega.github.io/vega-lite/docs/selection.html Vega-Lite documentation>.++@+selection = selection . select "view" Interval [ BindScales ]+@+-}+selection :: [LabelledSpec] -> (VLProperty, VLSpec)+selection sels = (VLSelection, object sels)+++{-|++Defines a specification object for use with faceted and repeated small multiples.++@+toVegaLite+    [ facet [ RowBy [ FName \"Origin\", FmType Nominal ] ]+    , specifcation spec+    ]+@+-}+specification :: VLSpec -> (VLProperty, VLSpec)+specification spec = (VLSpec, spec)+++{-|++Create a single transform from a list of transformation specifications. Note+that the order of transformations can be important, especially if labels created+with 'calculateAs', 'timeUnitAs', and 'binAs' are used in other transformations.+Using the functional composition pipeline idiom (as example below) allows you to+provide the transformations in the order intended in a clear manner.++@+trans = transform+        . filter (FExpr "datum.year == 2010")+        . calculateAs "datum.sex == 2 ? 'Female' : 'Male'" "gender"+@+-}++transform :: [LabelledSpec] -> (VLProperty, VLSpec)+transform transforms =+  let js = if null transforms then A.Null else toJSON (map assemble transforms)++      -- use the same approach as Elm of encoding the spec, then decoding it,+      -- rather than inspecting the structure of the JSON+      --+      assemble :: LabelledSpec -> VLSpec+      assemble (str, val) =++        let dval = decode (encode val)+        in case str of+          "aggregate" ->+            case dval of+              Just (A.Array vs) | V.length vs == 2 -> object [ ("aggregate", vs V.! 0)+                                                             , ("groupby", vs V.! 1) ]+              _ -> A.Null++          "bin" ->+            case dval of+              Just (A.Array vs) | V.length vs == 3 -> object [ ("bin", vs V.! 0)+                                                             , ("field", vs V.! 1)+                                                             , ("as", vs V.! 2) ]+              _ -> A.Null++          "calculate" ->+            case dval of+              Just (A.Array vs) | V.length vs == 2 -> object [ ("calculate", vs V.! 0)+                                                             , ("as", vs V.! 1) ]+              _ -> A.Null++          "lookup" ->+            case dval of+              Just (A.Array vs) | V.length vs == 4 -> object [ ("lookup", vs V.! 0)+                                                             , ("from",+                                                                object [ ("data", vs V.! 1)+                                                                       , ("key", vs V.! 2)+                                                                       , ("fields", vs V.! 3) ] )+                                                             ]+              _ -> A.Null++          "lookupAs" ->+            case dval of+              Just (A.Array vs) | V.length vs == 4 -> object [ ("lookup", vs V.! 0)+                                                             , ("from",+                                                                object [ ("data", vs V.! 1)+                                                                       , ("key", vs V.! 2) ] )+                                                             , ("as", vs V.! 3) ]+              _ -> A.Null++          "timeUnit" ->+            case dval of+              Just (A.Array vs) | V.length vs == 3 -> object [ ("timeUnit", vs V.! 0)+                                                             , ("field", vs V.! 1)+                                                             , ("as", vs V.! 2) ]+              _ -> A.Null++          _ -> object [(str, val)]+                +    in (VLTransform, js)       +++{-|++Assigns a list of specifications to be juxtaposed vertically in a visualization.++@+toVegaLite+    [ dataFromUrl "data/driving.json" []+    , vConcat [ spec1, spec2 ]+    ]+@+-}+vConcat :: [VLSpec] -> (VLProperty, VLSpec)+vConcat specs = (VLVConcat, toJSON specs)+++{-|++Override the default width of the visualization. If not specified the width+will be calculated based on the content of the visualization.++@+toVegaLite+    [ width 500+    , dataFromUrl "data/population.json" []+    , mark Bar []+    , enc []+    ]+@+-}+width :: Double -> (VLProperty, VLSpec)+width w = (VLWidth, toJSON w)+++{-|++Defines a set of named aggregation transformations to be used when encoding+channels. This is useful when, for example, you wish to apply the same transformation+to a number of channels but do not want to define it each time. For further details+see the+<https://vega.github.io/vega-lite/docs/aggregate.html#aggregate-op-def Vega-Lite documentation>.++@+trans =+    transform+        . aggregate+            [ opAs Min "people" "lowerBound", opAs Max "people" "upperBound" ]+            [ "age" ]+@+-}+aggregate ::+  [VLSpec]+  -- ^ The named aggregation operations to apply.+  -> [T.Text]+  -- ^ The \"group by\" fields.+  -> BuildLabelledSpecs+aggregate ops groups ols =+  let ags = toJSON [toJSON ops, toJSON (map toJSON groups)]+  in ("aggregate", ags) : ols+++{-|++Create a named binning transformation that may be referenced in other Transformations+or encodings. See the+<https://vega.github.io/vega-lite/docs/bin.html Vega-Lite documentation> for+more details. Note that usually, direct binning within an encoding is preferred+over this form of bin transformation.++@+trans =+    transform+        . binAs [ MaxBins 3 ] \"IMDB_Rating\" "ratingGroup"+@+-}+binAs ::+  [BinProperty]+  -- ^ An empty list means that the default binning is used.+  -> T.Text+  -- ^ The field to bin.+  -> T.Text+  -- ^ The label for the binned data.+  -> BuildLabelledSpecs+binAs bProps field label ols =+  let js = if null bProps+           then [toJSON True, toJSON field, toJSON label]+           else [object (map binProperty bProps), toJSON field, toJSON label]+ in ("bin" .= js) : ols+++{-|++Creates a new data field based on calculations from existing fields.+See the <https://vega.github.io/vega-lite/docs/calculate.html Vega-Lite documentation>+for further details.++@+trans =+    transform . calculateAs "datum.sex == 2 ? 'F' : 'M'" "gender"+@+-}+calculateAs ::+  T.Text+  -- ^ The calculation to perform.+  -> T.Text+  -- ^ The field to assign the new values.+  -> BuildLabelledSpecs+calculateAs expr label ols = ("calculate" .= [expr, label]) : ols+++{-|++Encode a color channel.++@+color [ MName \"Species\", MmType Nominal ] []+@++Encoding a color channel will generate a legend by default. To stop the legend+appearing, just supply an empty list of legend properties to 'MLegend':++@+color [ MName \"Species\", MmType Nominal, MLegend [] ] []+@+-}+color ::+  [MarkChannel]+  -- ^ Control how the data field is encoded by color.+  -> BuildLabelledSpecs+color markProps ols =+  let cs = object (concatMap markChannelProperty markProps)+  in ("color", cs) : ols +++{-|++Encodes a new facet to be arranged in columns.++@+enc =+    encoding+        . position X [ PName "people", PmType Quantitative ]+        . position Y [ PName "gender", PmType Nominal ]+        . column [ FName "age", FmType Ordinal ]+@+-}+column ::+  [FacetChannel]+  -- ^ The list of properties that define the faceting channel. At a minimum+  --   this should include the data field ('FName') and its measurement type+  --   ('FmType').+  -> BuildLabelledSpecs+column fFields ols =+  ("column" .= object (map facetChannelProperty fFields)) : ols+++{-|++Defines a single configuration option to be applied globally across the visualization.+The first parameter identifies the type of configuration, the second a list of previous+configurations to which this one may be added.++@+configuration (Axis [ DomainWidth 4 ]) []+@+-}+configuration :: ConfigurationProperty -> BuildLabelledSpecs+configuration cfg ols = configProperty cfg : ols+++{-|++Encode a \"level of detail\" channel. This provides a way of grouping by a field+but unlike, say 'color', all groups have the same visual properties. The first+parameter is a list of the field characteristics to be grouped. The second parameter+is a list of any previous channels to which this detail channel should be added. See the+<https://vega.github.io/vega-lite/docs/encoding.html#detail Vega-Lite documentation>+for details.++@+detail [ DName \"Species\", DmType Nominal ] []+@+-}+detail :: [DetailChannel] -> BuildLabelledSpecs+detail detailProps ols =+    ("detail" .= object (map detailChannelProperty detailProps)) : ols+++{-|++Encode a fill channel. This acts in a similar way to encoding by 'color' but+only affects the interior of closed shapes. The first parameter is a list of mark+channel properties that characterise the way a data field is encoded by fill.+The second parameter is a list of any previous channels to which this fill channel+should be added.++@+fill [ MName \"Species\", MmType Nominal ] []+@++Note that if both @fill@ and 'color' encodings are specified, @fill@ takes precedence.++-}+fill :: [MarkChannel] -> BuildLabelledSpecs+fill markProps ols =+  ("fill" .= object (concatMap markChannelProperty markProps)) : ols+++{-|++Adds the given filter operation a list of transformations that may be applied+to a channel or field. The first parameter is the filter operation and the second,+often implicit, parameter is the list of other filter operations to which this+should be added in sequence.++@+trans =+    transform+        . filter (FEqual \"Animal\" (Str \"Cat\"))+@++Filter operations can combine selections and data predicates with 'BooleanOp'+expressions:++@+trans =+    transform+        . filter (FCompose (And (Expr "datum.Weight_in_lbs > 3000") (Selection "brush")))+@+-}+filter :: Filter -> BuildLabelledSpecs+filter f ols =+  let js = case f of+        FExpr expr -> toJSON expr+        FCompose boolExpr -> booleanOpSpec boolExpr++        FEqual field val -> object [field_ field, "equal" .= dataValueSpec val]++        FSelection selName -> object ["selection" .= selName]++        FRange field vals ->+            let ans = case vals of+                        NumberRange mn mx -> map toJSON [mn, mx]+                        DateRange dMin dMax ->+                          [ object (map dateTimeProperty dMin)+                          , object (map dateTimeProperty dMax)+                          ]+            in object [field_ field, "range" .= ans]++        FOneOf field vals ->+            let ans = case vals of+                        Numbers xs -> map toJSON xs+                        DateTimes dts -> map (object . map dateTimeProperty) dts+                        Strings ss -> map toJSON ss+                        Booleans bs -> map toJSON bs+                  +            in object [field_ field, "oneOf" .= ans]++  in ("filter", js) : ols +++{-|++Encode a hyperlink channel. The first parameter is a list of hyperlink channel+properties that characterise the hyperlinking such as the destination url and cursor+type. The second parameter is a list of any previous encoding channels to which+this hyperlink channel should be added.++@+hyperlink [ HName \"Species\", HmType Nominal ] []+@++For further details see the+<https://vega.github.io/vega-lite/docs/encoding.html#href Vega-Lite documentation>.++-}+hyperlink :: [HyperlinkChannel] -> BuildLabelledSpecs+hyperlink hyperProps ols =+  ("href" .= object (concatMap hyperlinkChannelProperty hyperProps)) : ols+++{-|++Perform a lookup of named fields between two data sources. This allows you to+find values in one data source based on the values in another (like a relational+join).++Unlike 'lookupAs', this function will only return the specific fields named in the+fourth parameter. If you wish to return the entire set of fields in the secondary+data source as a single object, use 'lookupAs'.++See the <https://vega.github.io/vega-lite/docs/lookup.html Vega-Lite documentation>+for further details.++The following would return the values in the @age@ and @height@ fields from+@lookup_people.csv@ for all rows where the value in the @name@ column in that+file matches the value of @person@ in the primary data source.++@+trans =+    transform+        . lookup "person" (dataFromUrl "data/lookup_people.csv" []) "name" [ "age", "height" ]+@+-}+lookup ::+  T.Text+  -- ^ The field in the primary data structure acting as the key.+  -> Data+  -- ^ The secondary data source (e.g. the return from the data-generating+  --   functions such as 'dataFromUrl').+  -> T.Text+  -- ^ The name of the field in the secondary data source to match against+  --   the primary key.+  -> [T.Text]+  -- ^ The list of fields to store when the keys match.+  -> BuildLabelledSpecs+lookup key1 (_, spec) key2 fields ols =+  let js = [toJSON key1, spec, toJSON key2, toJSON (map toJSON fields)]+  in ("lookup" .= js) : ols+++{-|++Perform an object lookup between two data sources. This allows you to find+values in one data source based on the values in another (like a relational+join).++Unlike 'lookup', this function returns the entire set of field values from the+secondary data source when keys match. Those fields are stored as an object with+the name provided in the fourth parameter.++See the+<https://vega.github.io/vega-lite/docs/lookup.html Vega-Lite documentation>+for further details.++In the following example, @personDetails@ would reference all the field values in+@lookup_people.csv@ for each row where the value in the @name@ column in that+file matches the value of @person@ in the primary data source.++@+trans = transform+        . lookupAs "person" (dataFromUrl "data/lookup_people.csv" []) "name" "personDetails"+@+-}+lookupAs ::+  T.Text+  -- ^ The field in the primary data structure acting as the key.+  -> Data+  -- ^ The secondary data source (e.g. the return from the data-generating+  --   functions such as 'dataFromUrl').+  -> T.Text+  -- ^ The name of the field in the secondary data source to match against+  --   the primary key.+  -> T.Text+  -- ^ The field name for the new data. +  -> BuildLabelledSpecs+lookupAs key1 (_, spec) key2 asName ols =+  ("lookupAs" .= [toJSON key1, spec, toJSON key2, toJSON asName]) : ols+++{-|++Encode an opacity channel. The first parameter is a list of mark channel properties+that characterise the way a data field is encoded by opacity. The second parameter+is a list of any previous channels to which this opacity channel should be added.++@+opacity [ MName \"Age\", MmType Quantitative ] []+@+-}+opacity :: [MarkChannel] -> BuildLabelledSpecs+opacity markProps ols =+  ("opacity" .= object (concatMap markChannelProperty markProps)) : ols+++{-|++Encode an order channel. The first parameter is a list of order field definitions+to define the channel. The second parameter is a list of any previous channels to+which this order channel is to be added.++@+enc =+    encoding+        . position X [ PName "miles", PmType Quantitative ]+        . position Y [ PName "gas", PmType Quantitative ]+        . order [ OName "year", OmType Temporal ]+@+-}+order :: [OrderChannel] -> BuildLabelledSpecs+order oDefs ols =+  ("order" .= object (map orderChannelProperty oDefs)) : ols+++{-|++Encode a position channel.++@+enc =+    encoding+      . position X [ PName \"Animal\", PmType Ordinal ]+@++Encoding by position will generate an axis by default. To prevent the axis from+appearing, simply provide an empty list of axis properties to 'PAxis':++@+enc =+    encoding+      . position X [ PName \"Animal\", PmType Ordinal, PAxis [] ]+@+-}+position ::+  Position+  -- ^ The channel to encode.+  -> [PositionChannel]+  -- ^ The options for the channel; this will usually include the name ('PName')+  --    and measurement type ('PmType'), but can be a reference to a row or+  --    column repeat field.+  -> BuildLabelledSpecs+position pos pDefs ols =+  let defs = object (map positionChannelProperty pDefs)+  in (positionLabel pos, defs) : ols+++{-|++Define a single resolution option to be applied when scales, axes or legends+in composite views share channel encodings. This allows, for example, two different+color encodings to be created in a layered view, which otherwise by default would+share color channels between layers. Each resolution rule should be in a tuple+pairing the channel to which it applies and the rule type.++@+resolve+    . resolution (RScale [ ( ChY, Independent ) ])+@+-}+resolution :: Resolve -> BuildLabelledSpecs+resolution res ols = resolveProperty res : ols+++{-|++Encode a new facet to be arranged in rows.++@+enc =+    encoding+        . position X [ PName "people", PmType Quantitative ]+        . position Y [ PName "gender", PmType Nominal ]+        . row [ FName "age", FmType Ordinal ]+@+-}+row ::+  [FacetChannel]+  -- ^ The facet properties for the channel; this should include the name of+  --   the field ('FName') and its measurement type ('FmType').+  -> BuildLabelledSpecs+row fFields ols = ("row" .= object (map facetChannelProperty fFields)) : ols+++{-|++Create a single named selection that may be applied to a data query or transformation.++@+sel =+    selection+        . select "view" Interval [ BindScales ] []+        . select "myBrush" Interval []+        . select "myPaintbrush" Multi [ On "mouseover", Nearest True ]+@+-}+select ::+  T.Text+  -- ^ The name given to the selection.+  -> Selection+  -- ^ The type of the selection.+  -> [SelectionProperty]+  -- ^ What options are applied to the selection.+  -> BuildLabelledSpecs+select nme sType options ols =+    let selProps = ("type" .= selectionLabel sType) : map selectionProperty options+    in (nme .= object selProps) : ols+++{-|++Encode a shape channel.++@+shape [ MName \"Species\", MmType Nominal ] []+@+-}+shape ::+  [MarkChannel]+  -- ^ What data values are used to control the shape parameters of the mark.+  -> BuildLabelledSpecs+shape markProps ols = ("shape" .= object (concatMap markChannelProperty markProps)) : ols+++{-|++Encode a size channel.++@+size [ MName \"Age\", MmType Quantitative ] []+@+-}+size ::+  [MarkChannel]+  -- ^ What data values are used to control the size parameters of the mark.+  -> BuildLabelledSpecs+size markProps ols = ("size" .= object (concatMap markChannelProperty markProps)) : ols+++{-|++Encode a stroke channel. This acts in a similar way to encoding by 'color' but+only affects the exterior boundary of marks.++@+stroke [ MName \"Species\", MmType Nominal ] []+@++Note that if both @stroke@ and 'color' encodings are specified, @stroke@ takes+precedence.++-}+stroke ::+  [MarkChannel]+  -- ^ What data values are used to control the stoke parameters of the mark.+  -> BuildLabelledSpecs+stroke markProps ols =+  ("stroke" .= object (concatMap markChannelProperty markProps)) : ols+++{-|++Encode a text channel. See the+<https://vega.github.io/vega-lite/docs/encoding.html#text Vega-Lite documentation>+for further details on the text and tooltip channels and+<https://vega.github.io/vega-lite/docs/format.html Vega-Lite formatting documentation>+for formatting the appearance of the text.++@+enc =+    encoding+        . position X [ PName "miles", PmType Quantitative ]+        . position Y [ PName "gas", PmType Quantitative ]+        . text [ TName "miles", TmType Quantitative ]+@+-}+text ::+  [TextChannel]+  -- ^ What data values are used to control the text parameters.+  -> BuildLabelledSpecs+text tDefs ols =+  ("text" .= object (concatMap textChannelProperty tDefs)) : ols+++{-|++Creates a new data field based on the given temporal binning. Unlike the+direct encoding binning, this transformation is named and so can be referred+to in multiple encodings. Note though that usually it is easer to apply the temporal+binning directly as part of the encoding as this will automatically format the+temporal axis. See the+<https://vega.github.io/vega-lite/docs/timeunit.html#transform Vega-Lite documentation>+for further details.++The following example takes a temporal dataset and encodes daily totals from it+grouping by month:++@+trans = transform . timeUnitAs Month "date" "monthly"++enc = encoding+        . position X [ PName "date", PmType Temporal, PTimeUnit Day ]+        . position Y [ PAggregate Sum, PmType Quantitative ]+        . detail [ DName "monthly", DmType Temporal ]+@+-}+timeUnitAs ::+  TimeUnit+  -- ^ The width of each bin.+  -> T.Text+  -- ^ The field to bin.+  -> T.Text+  -- ^ The name of the binned data created by this routine.+  -> BuildLabelledSpecs+timeUnitAs tu field label ols =+  ("timeUnit" .= [timeUnitLabel tu, field, label]) : ols+++{-|++Encode a tooltip channel. See the+<https://vega.github.io/vega-lite/docs/encoding.html#text Vega-Lite documentation>+for further details on the text and tooltip channels and+<https://vega.github.io/vega-lite/docs/format.html Vega-Lite formatting documentation>+for formatting the appearance of the text.++@+enc = encoding+        . position X [ PName \"Horsepower\", PmType Quantitative ]+        . position Y [ PName \"Miles_per_Gallon\", PmType Quantitative ]+        . tooltip [ TName \"Year\", TmType Temporal, TFormat "%Y" ]+@+-}+tooltip ::+  [TextChannel]+  -- ^ The properties for the channel.+  -> BuildLabelledSpecs+tooltip tDefs ols =+  ("tooltip" .= object (concatMap textChannelProperty tDefs)) : ols