packages feed

hvega 0.5.0.0 → 0.6.0.0

raw patch · 131 files changed

+11442/−924 lines, 131 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Graphics.Vega.VegaLite: ConcatColumns :: Int -> ConcatConfig
- Graphics.Vega.VegaLite: ConcatSpacing :: Double -> ConcatConfig
- Graphics.Vega.VegaLite: FColumns :: Int -> FacetConfig
- Graphics.Vega.VegaLite: data ConcatConfig
- Graphics.Vega.VegaLite: data FacetConfig
+ Graphics.Vega.VegaLite: AStyle :: [StyleLabel] -> AxisConfig
+ Graphics.Vega.VegaLite: AlignBaseline :: VAlign
+ Graphics.Vega.VegaLite: AutosizeStyle :: [Autosize] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: AxLabelOffset :: Double -> AxisProperty
+ Graphics.Vega.VegaLite: AxStyle :: [StyleLabel] -> AxisProperty
+ Graphics.Vega.VegaLite: AxisDiscrete :: [AxisConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: AxisNamedStyles :: [(StyleLabel, [AxisProperty])] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: AxisPoint :: [AxisConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: AxisQuantitative :: [AxisConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: AxisTemporal :: [AxisConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: BackgroundStyle :: Color -> ConfigurationProperty
+ Graphics.Vega.VegaLite: BoxplotStyle :: [MarkProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: CAxLabelOffset :: Double -> Double -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelPadding :: Double -> Double -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxTickSize :: Double -> Double -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: ChStrokeDash :: Channel
+ Graphics.Vega.VegaLite: CompColumns :: Int -> CompositionConfig
+ Graphics.Vega.VegaLite: CompSpacing :: Double -> CompositionConfig
+ Graphics.Vega.VegaLite: CountTitleStyle :: Text -> ConfigurationProperty
+ Graphics.Vega.VegaLite: DUnionWith :: ScaleDomain -> ScaleDomain
+ Graphics.Vega.VegaLite: ErrorBandStyle :: [MarkProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: ErrorBarStyle :: [MarkProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: FAlign :: CompositionAlignment -> FacetChannel
+ Graphics.Vega.VegaLite: FCenter :: Bool -> FacetChannel
+ Graphics.Vega.VegaLite: FieldTitleStyle :: FieldTitleProperty -> ConfigurationProperty
+ Graphics.Vega.VegaLite: FontStyle :: Text -> ConfigurationProperty
+ Graphics.Vega.VegaLite: HLabel :: Bool -> HeaderProperty
+ Graphics.Vega.VegaLite: HLabelExpr :: VegaExpr -> HeaderProperty
+ Graphics.Vega.VegaLite: HLabelFontStyle :: Text -> HeaderProperty
+ Graphics.Vega.VegaLite: HTitleFontStyle :: Text -> HeaderProperty
+ Graphics.Vega.VegaLite: HTitleLineHeight :: Double -> HeaderProperty
+ Graphics.Vega.VegaLite: HeaderColumnStyle :: [HeaderProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: HeaderFacetStyle :: [HeaderProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: HeaderRowStyle :: [HeaderProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: ImageStyle :: [MarkProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: LabelOffset :: Double -> AxisConfig
+ Graphics.Vega.VegaLite: LeSymbolLimit :: Int -> LegendConfig
+ Graphics.Vega.VegaLite: LeTickCount :: Int -> LegendConfig
+ Graphics.Vega.VegaLite: LeTitleLineHeight :: Double -> LegendConfig
+ Graphics.Vega.VegaLite: LeUnselectedOpacity :: Opacity -> LegendConfig
+ Graphics.Vega.VegaLite: LegendStyle :: [LegendConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: MCornerRadiusEnd :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MNoBorders :: MarkProperty
+ Graphics.Vega.VegaLite: MNoBox :: MarkProperty
+ Graphics.Vega.VegaLite: MNoMedian :: MarkProperty
+ Graphics.Vega.VegaLite: MNoRule :: MarkProperty
+ Graphics.Vega.VegaLite: MNoTicks :: MarkProperty
+ Graphics.Vega.VegaLite: MSymbol :: Symbol -> MarkChannel
+ Graphics.Vega.VegaLite: MTexts :: [Text] -> MarkProperty
+ Graphics.Vega.VegaLite: MarkNamedStyles :: [(StyleLabel, [MarkProperty])] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: NumberFormatStyle :: Text -> ConfigurationProperty
+ Graphics.Vega.VegaLite: PaddingStyle :: Padding -> ConfigurationProperty
+ Graphics.Vega.VegaLite: ProjectionStyle :: [ProjectionProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: RNumberLists :: [[Double]] -> ScaleRange
+ Graphics.Vega.VegaLite: RangeStyle :: [RangeConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: RepeatStyle :: [CompositionConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: SCXReverse :: Bool -> ScaleConfig
+ Graphics.Vega.VegaLite: SDomainMid :: Double -> ScaleProperty
+ Graphics.Vega.VegaLite: SMCursor :: Cursor -> SelectionMarkProperty
+ Graphics.Vega.VegaLite: SReverse :: Bool -> ScaleProperty
+ Graphics.Vega.VegaLite: ScaleStyle :: [ScaleConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: TUMaxBins :: Natural -> TimeUnit
+ Graphics.Vega.VegaLite: TUStep :: Double -> TimeUnit -> TimeUnit
+ Graphics.Vega.VegaLite: TimeFormatStyle :: Text -> ConfigurationProperty
+ Graphics.Vega.VegaLite: VBNoFill :: ViewBackground
+ Graphics.Vega.VegaLite: VBNoStroke :: ViewBackground
+ Graphics.Vega.VegaLite: ViewCursor :: Cursor -> ViewConfig
+ Graphics.Vega.VegaLite: ViewNoFill :: ViewConfig
+ Graphics.Vega.VegaLite: ViewNoStroke :: ViewConfig
+ Graphics.Vega.VegaLite: ViewStyle :: [ViewConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: data CompositionConfig
+ Graphics.Vega.VegaLite: strokeDash :: [MarkChannel] -> BuildEncodingSpecs
+ Graphics.Vega.VegaLite: type StyleLabel = Text
- Graphics.Vega.VegaLite: ConcatStyle :: [ConcatConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: ConcatStyle :: [CompositionConfig] -> ConfigurationProperty
- Graphics.Vega.VegaLite: FSpacing :: Double -> FacetConfig
+ Graphics.Vega.VegaLite: FSpacing :: Double -> FacetChannel
- Graphics.Vega.VegaLite: FacetStyle :: [FacetConfig] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: FacetStyle :: [CompositionConfig] -> ConfigurationProperty
- Graphics.Vega.VegaLite: MStyle :: [Text] -> MarkProperty
+ Graphics.Vega.VegaLite: MStyle :: [StyleLabel] -> MarkProperty
- Graphics.Vega.VegaLite: NamedStyle :: Text -> [MarkProperty] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: NamedStyle :: StyleLabel -> [MarkProperty] -> ConfigurationProperty
- Graphics.Vega.VegaLite: NamedStyles :: [(Text, [MarkProperty])] -> ConfigurationProperty
+ Graphics.Vega.VegaLite: NamedStyles :: [(StyleLabel, [MarkProperty])] -> ConfigurationProperty
- Graphics.Vega.VegaLite: TStyle :: [Text] -> TitleConfig
+ Graphics.Vega.VegaLite: TStyle :: [StyleLabel] -> TitleConfig
- Graphics.Vega.VegaLite: VBFill :: Maybe Color -> ViewBackground
+ Graphics.Vega.VegaLite: VBFill :: Color -> ViewBackground
- Graphics.Vega.VegaLite: VBStroke :: Maybe Color -> ViewBackground
+ Graphics.Vega.VegaLite: VBStroke :: Color -> ViewBackground
- Graphics.Vega.VegaLite: VBStyle :: [Text] -> ViewBackground
+ Graphics.Vega.VegaLite: VBStyle :: [StyleLabel] -> ViewBackground
- Graphics.Vega.VegaLite: ViewFill :: Maybe Color -> ViewConfig
+ Graphics.Vega.VegaLite: ViewFill :: Color -> ViewConfig
- Graphics.Vega.VegaLite: ViewStroke :: Maybe Color -> ViewConfig
+ Graphics.Vega.VegaLite: ViewStroke :: Color -> ViewConfig

Files

CHANGELOG.md view
@@ -1,6 +1,116 @@ For the latest version of this document, please see [https://github.com/DougBurke/hvega/blob/master/hvega/CHANGELOG.md](https://github.com/DougBurke/hvega/blob/master/hvega/CHANGELOG.md). +## 0.6.0.0++The Vega-Lite tests are now validated against version 4.5 of the+Vega-Lite schema.++### New functionality++New function for use with `encoding`: `strokeDash`. The `ChStrokeDash`+constructor has been added to the `Channel` type, and `RNumberLists`+(Vega-Lite 4.4) to `ScaleRange`.++Named styles have been added for axes as well as marks. As mentioned+below, this involves deprecating the previous constructors for naming+styles, as there are now separate configuration options:+`AxisNamedStyles` and `MarkNamedStyles`. The `AStyle` and `AxStyle`+options have been added to `AxisConfig` and `AxisProperty`+respectively.  The `StyleLabel` type alias has been added to help the+documentation, but provides no extra type safety.++### Breaking changes++The `ConcatStyle` and `FacetStyle` constructors for+`ConfigurationProperty` now accept a common type,+`CompositionConfig`, rather than having separate+`ConcatConfig` and `FacetConfig` types with the same meaning.+So `ConcatColumns` and `FColumns` have been replaced by `CompColumns`,+and `CompSpacing` and `FSpacing` by `CompSpacing`.++The `ViewFill` and `ViewStroke` constructors of `ViewConfig` no longer+take an optional `Color` argument. The Nothing case has been replaced+by new constructors: `ViewNoFill` and `ViewNoStroke`.++The `VBFill` and `VBStroke` constructors of `ViewBackground` no longer+take an optional `Color` argument. The Nothing case has been replaced+by new constructors: `VBNoFill` and `VBNoStroke`.++### New constructors++`FacetChannel` has gained the following constructors: `FAlign`,+`FCenter`, and `FSpacing`. The last one would have collides with+the `FacetStyle` option, but this has fortuitously been renamed to+`CompSpacing`.++`MSymbol` has been added to `MarkChannel` which can be used to make the+`shape` encoding conditional on a data or selection condition.++The `TUStep` and `TUMaxBins` constructors have been added to `TimeUnit`+for controlling how time values are binned.++The `MarkProperty` type has gained the `MCornerRadiusEnd` constructor,+which is used to draw rounded histogram bars, and `MTexts` for+specifying multiple text values.++Error box and band properties (constructors in `MarkProperty`) can now+be turned off with explicit `No` variants: `MNoBorders`, `MNoBox`,+`MNoMedian`, `MNoRule`, and `MNoTicks`. These join the `MNoOutliers`+constructor.++The `ScaleProperty` type has gained `SDomainMid`, useful for+asymmetric diverging color scales, and `SReverse` from Vega-Lite v4.5.+The `ScaleDomain` type has gained the `DUnionWith` option from+Vega-Lite v4.3. The `ScaleConfig` type has gained `SCXReverse`+from Vega-Lite v4.5.++Labels can now be vertically aligned to their baseline with the+`AlignBaseline` constructor of the `VAlign` type.++Headers (`HeaderProperty`) have gained the following constructors:+`HLabel`, `HLabelExpr`, `HLabelFontStyle`, `HTitleFontStyle`,+and `HTitleLineHeight`.++Conditional axis (`ConditionalAxisProperty`) has gained the following+constructors for features added in Vega-Lite v4.2 and v4.5:+`CAxLabelOffset`, `CAxLabelPadding`, and `CAxTickSize`.++Cursor handling has been enhanced (to match Vega-Lite 4.1):+`ViewCursor` has been added to `ViewConfig` and `SMCursor` to+`SelectionMarkProperty`.++The legend configuration has been updated (to match Vega-Lite 4.0)+with the addition of `LeSymbolLimit`, `LeTickCount`, `LeTitleLineHeight`,+and `LeUnselectedOpacity` constructors.++The axis configuration and property types (`AxisConfig` and+`AxisProperty`) have gained the Vega-Lite 4.4 `LabelOffset` and+`AxLabelOffset` constructors.  Note that version 4.4.0 of the+Vega-Lite specification has these fields as strings but this is fixed+in version 4.5.0.++`ConfigurationProperty` has added new constructors: `AxisDiscrete` and+`AxisPoint` from Vega-Lite 4.5, `AxisQuantitative` and `AxisTemporal`+from Vega-Lite 4.4, `BoxplotStyle`, `ErrorBandStyle`, `ErrorBarStyle`,+`FontStyle` (Vega-Lite 4.3), `HeaderColumnStyle`, `HeaderFacetStyle`,+`HeaderRowStyle`, `ImageStyle`, and `RepeatStyle`.++### Deprecated symbols++`ConfigurationProperty` has seen a large number of deprecations, as a+number of constructors have been renamed:++ - The `NamedStyle` and `NamedStyles` have been replaced by `MarkNamedStyles`;++ - `Autosize`, `Background`, `CountTitle`, `FieldTitle`, `Legend`,+   `NumberFormat`, `Padding`, `Projection`, `Range`, `Scale`,+   `TimeFormat`, and `View` constructors have been replaced by+   `AutosizeStyle`, `BackgroundStyle`, `CountTitleStyle`,+   `FieldTitleStyle`, `LegendStyle`, `NUmberFormatStyle`,+   `PaddingStyle`, `ProjectionStyle`, `RangeStyle`, `ScaleStyle`,+   `TimeFormatStyle`, `ViewStyle` respectively.+ ## 0.5.0.0  Update to version 4.0 of the Vega-Lite specification (tested against
README.md view
@@ -1,7 +1,9 @@ # hvega +[![vega-lite version](https://img.shields.io/badge/Vega--Lite-v4.5-purple.svg)](https://vega.github.io/vega-lite/)+ Create [Vega-Lite](https://vega.github.io/vega-lite/) visualizations in-Haskell. It targets version 4 of the Vega-Lite specification. Note that+Haskell. It targets version 4.5 of the Vega-Lite specification. Note that the module does not include a viewer for these visualizations (which are JSON files), but does provide several helper functions, such as [toHtmlFile](https://hackage.haskell.org/package/hvega/docs/Graphics-Vega-VegaLite.html#v:toHtmlFile),
hvega.cabal view
@@ -1,5 +1,5 @@ name:                hvega-version:             0.5.0.0+version:             0.6.0.0 synopsis:            Create Vega-Lite visualizations (version 4) in Haskell. description:         This is based on the elm-vegalite package                      (<http://package.elm-lang.org/packages/gicentre/elm-vegalite/latest>)@@ -174,6 +174,7 @@                        ConditionalTests                        ConfigTests                        DataTests+                       EncodingTests                        FillStrokeTests                        GeoTests                        HyperlinkTests@@ -190,6 +191,7 @@                        TimeTests                        TooltipTests                        TrailTests+                       TransformTests                        ViewCompositionTests                        WindowTransformTests                        Gallery.Advanced
hvega.nix view
@@ -3,7 +3,7 @@ }: mkDerivation {   pname = "hvega";-  version = "0.5.0.0";+  version = "0.6.0.0";   src = ./.;   isLibrary = true;   isExecutable = true;
src/Graphics/Vega/Tutorials/VegaLite.hs view
@@ -521,7 +521,7 @@ -- Vega-Embed PNG and SVG output, is white (in Vega-Lite version 4; -- prior to this it was transparent). In many cases this is -- perfectly fine, but an explicit color can be specified using the--- 'Background' configuration option, as shown here, or with the+-- 'BackgroundStyle' configuration option, as shown here, or with the -- 'background' function, which is used in the choropleth examples -- below ('choroplethLookupToGeo'). @@ -543,7 +543,7 @@             . position X [ PName \"plx\", PmType Quantitative ]      conf = 'configure'-             . 'configuration' ('Background' "rgba(0, 0, 0, 0.1)")+             . 'configuration' ('BackgroundStyle' "rgba(0, 0, 0, 0.1)")  in toVegaLite     [ dataFromUrl \"https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv\" [TSV]@@ -557,7 +557,7 @@ and earlier), you would use  @-'configuration' ('Background' "rgba(0, 0, 0, 0)")+'configuration' ('BackgroundStyle' "rgba(0, 0, 0, 0)") @  -}@@ -567,7 +567,7 @@     [ dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]     , mark Tick []     , encoding (position X [ PName "plx", PmType Quantitative ] [])-    , configure (configuration (Background "rgba(0, 0, 0, 0.1)") [])+    , configure (configuration (BackgroundStyle "rgba(0, 0, 0, 0.1)") [])     ]  @@ -2409,7 +2409,7 @@     labelSpec = asSpec [ labelEnc [], mark 'Text' [ 'MdY' (-6) ] ]      cfg = configure-          . configuration ('View' ['ViewStroke' Nothing])+          . configuration ('ViewStyle' ['ViewNoStroke'])  in toVegaLite [ width 300               , height 250@@ -2467,7 +2467,7 @@       labelSpec = asSpec [ labelEnc [], mark Text [ MdY (-6) ] ]        cfg = configure-            . configuration (View [ViewStroke Nothing])+            . configuration (ViewStyle [ViewNoStroke])    in toVegaLite [ width 300                 , height 250@@ -2897,7 +2897,7 @@     s2 = rSpec 0 \"12\"     s3 = rSpec 120 \"4\" -    setup = configure . configuration (View [ ViewStroke Nothing ])+    setup = configure . configuration (ViewStyle [ ViewNoStroke ])  in toVegaLite [ setup []               , gaiaData@@ -2979,7 +2979,7 @@       s2 = rSpec 0 "12"       s3 = rSpec 120 "4" -      setup = configure . configuration (View [ ViewStroke Nothing ])+      setup = configure . configuration (ViewStyle [ ViewNoStroke ])    in toVegaLite [ setup []                 , gaiaData@@ -3671,7 +3671,7 @@                                    ]     conf = configure-            . configuration (Background "beige")+            . configuration (BackgroundStyle "beige")  in toVegaLite (conf [] :                sel [] :@@ -3705,7 +3705,7 @@                                      ]        conf = configure-               . configuration (Background "beige")+               . configuration (BackgroundStyle "beige")    in toVegaLite (conf [] :                  sel [] :@@ -5025,7 +5025,7 @@    , vConcat allSpecs      -- remove the "other" axis (e.g. top of Y, right for X)    , configure-       . configuration (View [ ViewStroke (Just \"transparent\") ])+       . configuration (ViewStyle [ 'ViewStroke' \"transparent\" ])        $ []    , title \"Gaia data from arXiv:1804.09378\" [ 'TAnchor' 'AMiddle' ]    ]@@ -5199,7 +5199,7 @@      , vConcat allSpecs      -- remove the "other" axis (e.g. top of Y, right for X)      , configure-         . configuration (View [ ViewStroke (Just "transparent") ])+         . configuration (ViewStyle [ ViewStroke "transparent" ])          $ []      , title "Gaia data from arXiv:1804.09378" [ TAnchor AMiddle ]      ]@@ -5739,10 +5739,10 @@ aitoffConfig :: [ConfigureSpec] -> PropertySpec aitoffConfig =   configure-  . configuration (View [ ViewStroke Nothing ])-  . configuration (FacetStyle [ FSpacing 0 ])+  . configuration (ViewStyle [ ViewNoStroke ])+  . configuration (FacetStyle [ CompSpacing 0 ])   . configuration (HeaderStyle [ HLabelAngle 0 ])-  . configuration (Legend [ LeOrient LOBottom, LeNoTitle ])+  . configuration (LegendStyle [ LeOrient LOBottom, LeNoTitle ])   . configuration (Axis [ Domain False                         , Grid False                         , Labels False@@ -5840,10 +5840,10 @@ --  aitoffConfig :: ['ConfigureSpec'] -> 'PropertySpec' --  aitoffConfig = --    configure---    . configuration (View [ ViewStroke Nothing ])---    . configuration ('FacetStyle' [ 'FSpacing' 0 ])+--    . configuration (ViewStyle [ ViewNoStroke ])+--    . configuration ('FacetStyle' [ 'CompSpacing' 0 ]) --    . configuration ('HeaderStyle' [ 'HLabelAngle' 0 ])---    . configuration ('Legend' [ 'LeOrient' LOBottom, 'LeNoTitle' ])+--    . configuration ('LegendStyle' [ 'LeOrient' LOBottom, 'LeNoTitle' ]) --    . configuration ('Axis' [ 'Domain' False --                          , 'Grid' False --                          , 'Labels' False
src/Graphics/Vega/VegaLite.hs view
@@ -134,6 +134,7 @@        , VL.GradientStops        , VL.Opacity        , VL.SelectionLabel+       , VL.StyleLabel        , VL.VegaExpr        , VL.ZIndex        , VL.toHtml@@ -400,15 +401,16 @@          --          -- $markprops -       , VL.size        , VL.color        , VL.fill-       , VL.stroke-       , VL.strokeWidth-       , VL.opacity        , VL.fillOpacity-       , VL.strokeOpacity+       , VL.opacity        , VL.shape+       , VL.size+       , VL.stroke+       , VL.strokeDash+       , VL.strokeOpacity+       , VL.strokeWidth           -- *** Mark Channel properties @@ -640,17 +642,11 @@        , VL.APosition(..)        , VL.FieldTitleProperty(..) -         -- ** Facet Configuration Options-         ---         -- $facetconfig--       , VL.FacetConfig(..)--         -- ** Concatenated View Configuration Options+         -- ** Composition Configuration Options          ---         -- $concatconfig+         -- $compositionconfig -       , VL.ConcatConfig(..)+       , VL.CompositionConfig(..)           -- * General Data types          --@@ -672,6 +668,10 @@          --          -- $update +         -- ** Version 0.6+         --+         -- $update0600+          -- ** Version 0.5          --          -- $update0500@@ -1035,13 +1035,13 @@ -- See the -- [Vega-Lite view configuration documentation](https://vega.github.io/vega-lite/docs/spec.html#config). --- $facetconfig--- See the--- [Vega-Lite facet configuration documentation](https://vega.github.io/vega-lite/docs/facet.html#facet-configuration).---- $concatconfig--- See the--- [Vega-Lite concat configuration documentation](https://vega.github.io/vega-lite/docs/concat.html#concat-configuration).+-- $compositionconfig+-- See the Vega-Lite+-- [concat](https://vega.github.io/vega-lite/docs/concat.html#concat-configuration),+-- [facet](https://vega.github.io/vega-lite/docs/facet.html#facet-configuration),+-- and+-- [repeat](https://vega.github.io/vega-lite/docs/repeat.html#repeat-configuration)+-- configuration documentation pages.  -- $generaldatatypes -- In addition to more general data types like integers and string, the following types@@ -1056,6 +1056,120 @@ -- The following section describes how to update code that used -- an older version of @hvega@. +-- $update0600+-- The @0.6.0.0@ release updates @hvega@ to support version 4.5 of+-- the Vega-Lite schema.+--+-- __New functionality__+--+-- New function for use with 'VL.encoding': 'VL.strokeDash'. The 'VL.ChStrokeDash'+-- constructor has been added to the 'VL.Channel' type, and 'VL.RNumberLists'+-- (Vega-Lite 4.4) to 'VL.ScaleRange'.+--+-- Named styles have been added for axes as well as marks. As mentioned below,+-- this involves deprecating the previous constructors for naming styles,+-- as there are now separate configuration options: 'VL.AxisNamedStyles'+-- and 'VL.MarkNamedStyles'. The 'VL.AStyle' and 'VL.AxStyle' options have been+-- added to 'VL.AxisConfig' and 'VL.AxisProperty' respectively.+-- The `VL.StyleLabel` type alias has been added to help the documentation, but+-- provides no extra type safety.+--+-- __Breaking Change__+--+-- The 'VL.ConcatStyle' and 'VL.FacetStyle' constructors for+-- 'VL.ConfigurationProperty' now accept a common type,+-- 'VL.CompositionConfig', rather than having separate+-- @ConcatConfig@ and @FacetConfig@ types with the same meaning.+-- So @ConcatColumns@ and @FColumns@ have been replaced by 'VL.CompColumns',+-- and @CompSpacing@ and @FSpacing@ by 'VL.CompSpacing'.+--+-- The 'VL.ViewFill' and 'VL.ViewStroke' constructors of 'VL.ViewConfig'+-- no longer take an optional 'VL.Color' argument. The @Nothing@+-- case has been replaced by new constructors: 'VL.ViewNoFill'+-- and 'VL.ViewNoStroke'.+--+-- The 'VL.VBFill' and 'VL.VBStroke' constructors of 'VL.ViewBackground'+-- no longer take an optional 'VL.Color' argument. The @Nothing@+-- case has been replaced by new constructors: 'VL.VBNoFill'+-- and 'VL.VBNoStroke'.+--+-- __New constructors__:+--+-- 'VL.FacetChannel' has gained the following constructors:+-- 'VL.FAlign', 'VL.FCenter', and 'VL.FSpacing'. The last one+-- would have collided with the @FacetStyle@ option,+-- but this has fortuitously been renamed to 'VL.CompSpacing'.+--+-- 'VL.MSymbol' has been added to 'VL.MarkChannel' which can be+-- used to make the 'VL.shape' encoding conditional on a data+-- or selection condition.+--+-- The 'VL.TUStep' and 'VL.TUMaxBins' constructors have been added to+-- 'VL.TimeUnit' for controlling how time values are binned.+--+-- The 'VL.MarkProperty' type has gained the 'VL.MCornerRadiusEnd'+-- constructor, which is used to draw rounded histogram bars, and+-- 'VL.MTexts' for specifying multiple text values.+--+-- Error box and band properties (constructors in 'VL.MarkProperty') can now+-- be turned off with explicit @No@ variants: 'VL.MNoBorders', 'VL.MNoBox',+-- 'VL.MNoMedian', 'VL.MNoRule', and 'VL.MNoTicks'. These join the 'VL.MNoOutliers'+-- constructor.+--+-- The 'VL.ScaleProperty' type has gained 'VL.SDomainMid', useful+-- for asymmetric diverging color scales, and 'VL.SReverse' from+-- Vega-Lite v4.5. The 'VL.ScaleDomain' type has gained the+-- 'VL.DUnionWith' option from Vega-Lite v4.3. The 'VL.ScaleConfig'+-- type has gained 'VL.SCXReverse' from Vega-Lite v4.5.+--+-- Labels can now be vertically aligned to their baseline with the+-- 'VL.AlignBaseline' constructor of the 'VL.VAlign' type.+--+-- Headers ('VL.HeaderProperty') have gained the following constructors:+-- 'VL.HLabel', 'VL.HLabelExpr', 'VL.HLabelFontStyle', 'VL.HTitleFontStyle',+-- and 'VL.HTitleLineHeight'.+--+-- Conditional axis ('VL.ConditionalAxisProperty') has gained the following+-- constructors for features added in Vega-Lite v4.2 and v4.5:+-- 'VL.CAxLabelOffset', 'VL.CAxLabelPadding', and 'VL.CAxTickSize'.+--+-- Cursor handling has been enhanced (to match Vega-Lite 4.1):+-- 'VL.ViewCursor' has been added to 'VL.ViewConfig' and 'VL.SMCursor' to+-- 'VL.SelectionMarkProperty'.+--+-- The legend configuration has been updated (to match Vega-Lite 4.0)+-- with the addition of 'VL.LeSymbolLimit', 'VL.LeTickCount', 'VL.LeTitleLineHeight',+-- and 'VL.LeUnselectedOpacity' constructors.+--+-- The axis configuration and property types ('VL.AxisConfig' and 'VL.AxisProperty')+-- have gained the Vega-Lite 4.4 'VL.LabelOffset' and 'VL.AxLabelOffset' constructors.+-- Note that version 4.4.0 of the Vega-Lite specification has these fields+-- as strings but this is fixed in version 4.5.0.+--+-- 'VL.ConfigurationProperty' has added new constructors:+-- 'VL.AxisDiscrete' and 'VL.AxisPoint' from Vega-Lite 4.5,+-- 'VL.AxisQuantitative' and 'VL.AxisTemporal' from Vega-Lite 4.4,+-- 'VL.BoxplotStyle', 'VL.ErrorBandStyle', 'VL.ErrorBarStyle',+-- 'VL.FontStyle' (Vega-Lite 4.3), 'VL.HeaderColumnStyle',+-- 'VL.HeaderFacetStyle', 'VL.HeaderRowStyle',+-- 'VL.ImageStyle', and 'VL.RepeatStyle'.+--+-- __Deprecated symbols__:+--+-- 'VL.ConfigurationProperty' has seen a large number of deprecations,+-- as a number of constructors have been renamed:+--+-- * @NamedStyle@ and @NamedStyles@ have been replaced by 'VL.MarkNamedStyles';+--+-- * @Autosize@, @Background@, @CountTitle@, @FieldTitle@,+--   @Legend@, @NumberFormat@, @Padding@, @Projection@, @Range@,+--   @Scale@, @TimeFormat@, and @View@+--   constructors have been replaced by+--   'VL.AutosizeStyle', 'VL.BackgroundStyle', 'VL.CountTitleStyle',+--   'VL.FieldTitleStyle', 'VL.LegendStyle', 'VL.NumberFormatStyle',+--   'VL.PaddingStyle', 'VL.ProjectionStyle', 'VL.RangeStyle',+--   'VL.ScaleStyle', 'VL.TimeFormatStyle', and 'VL.ViewStyle' respectively.+ -- $update0500 -- The @0.5.0.0@ release now creates specifications using version 4 -- of the Vega-Lite schema (version 0.4 of @hvega@ used version 3).@@ -1080,7 +1194,7 @@ --   previous versions it was transparent. If you --   need a transparent background then add the following configuration --   to the visualization:---   @'VL.configuration' ('VL.Background' \"rgba(0,0,0,0)\")@.+--   @'VL.configuration' ('VL.BackgroundStyle' \"rgba(0,0,0,0)\")@. -- -- * Tooltips are now disabled by default. To enable, either use the --   'VL.tooltip' channel or by setting @'VL.MTooltip' 'VL.TTEncoding'@.@@ -1178,8 +1292,8 @@ --   to @'VL.configuration' ('VL.View' ['VL.ViewStep' x])@. -- -- * The @ShortTimeLabels@, @LeShortTimeLabels@, and @MShortTImeLabels@---   constructors have been removed from `VL.AxisConfig`, `VL.LegendConfig`,---   and `VL.MarkProperty` respectively.+--   constructors have been removed from 'VL.AxisConfig', 'VL.LegendConfig',+--   and 'VL.MarkProperty' respectively. -- -- __New constructors__: --@@ -1474,7 +1588,8 @@ -- -- The 'VL.ConfigurationProperty' type, used with 'VL.configuration', has -- gained 'VL.ConcatStyle', 'VL.FacetStyle', 'VL.GeoshapeStyle', 'VL.HeaderStyle',--- 'VL.NamedStyles', and 'VL.TrailStyle' constructors.+-- @NamedStyles@ (renamed to 'VL.MarkNamedStyles' in 0.6.0.0),+-- and 'VL.TrailStyle' constructors. -- -- The 'VL.ConcatConfig' type was added for use with the 'VL.ConcatStyle', -- and the 'VL.FacetConfig' type for the 'VL.FacetStyle'
src/Graphics/Vega/VegaLite/Configuration.hs view
@@ -20,8 +20,7 @@        , FieldTitleProperty(..)         , ViewConfig(..)-       , FacetConfig(..)-       , ConcatConfig(..)+       , CompositionConfig(..)        , ScaleConfig(..)        , RangeConfig(..)        , AxisConfig(..)@@ -41,13 +40,15 @@  import Data.Aeson ((.=), object) - import Graphics.Vega.VegaLite.Core-  ( schemeProperty+  ( AxisProperty+  , axisProperty+  , schemeProperty   ) import Graphics.Vega.VegaLite.Foundation   ( Angle   , Color+  , StyleLabel   , CompositionAlignment   , DashStyle   , DashOffset@@ -68,6 +69,7 @@   , ZIndex   , HeaderProperty   , ViewBackground+  , Cursor   , fromColor   , fromDS   , splitOnNewline@@ -87,6 +89,7 @@   , paddingSpec   , autosizeProperty   , viewBackgroundSpec+  , cursorLabel   ) import Graphics.Vega.VegaLite.Geometry   ( ProjectionProperty@@ -127,6 +130,26 @@  Used by 'configuration'. +In @version 0.6.0.0@:++- the @Autosize@, @Background@, @CountTitle@, @FieldTitle@, @Legend@,+  @NumberFormat@, @Padding@, @Projection@, @Range@, @Scale@.+  @TimeFormat@, and @View@+  constructors have been deprecated, and should be replaced by+  'AutosizeStyle', 'BackgroundStyle', 'CountTitleStyle', 'FieldTitleStyle',+  'LegendStyle', 'NumberFormatStyle', 'PaddingStyle', 'ProjectionStyle',+  'RangeStyle', 'ScaleStyle', 'TimeFormatStyle', and 'ViewStyle'+  respectively. The axis configuration options have not been updated+  to this system.++- new constructors have been added: 'AxisDiscrete', 'AxisPoint',+  'AxisQuantitative', 'AxisTemporal', 'BoxplotStyle', 'ErrorBandStyle',+  'ErrorBarStyle', 'HeaderColumnStyle', 'HeaderFacetStyle', 'HeaderRowStyle',+  'ImageStyle', and 'RepeatStyle'.++- 'ConcatStyle' and 'FacetStyle' now take a common type, 'CompositionConfig',+  rather than @ConcatConfig@ and @FacetStyle@.+ In @version 0.5.0.0@:  - the @RemoveInvalid@ constructor was removed, as@@ -140,102 +163,217 @@  -} --- based on schema 3.3.0 #/definitions/Config------ TODO:---   Bar - change to BarConfig rather than MarkProperty?---     BoxplotStyle BoxPlotConfig---     Concat CompositionConfig---     ErrorBand ErrorBandCOnfig---     ErrorBar ErrorBarCOnfig---   Facet takes CompositionConfig not FacetConfig---     HeaderColumn takes HeaderConfig, just as HeaderStyle does---     HeaderFacet ditto---     HeaderRow ditto---   LineStyle takes LineConfig not MarkConfig---   TextStyle takes TextConfig not MarkConfig---   TickStyle takes TickConfig not MarkConfig---   TrailStyle takes LineConfig not MarkConfig---+{-# DEPRECATED Autosize "Please change Autosize to AutosizeStyle" #-}+{-# DEPRECATED Background "Please change Background to BackgroundStyle" #-}+{-# DEPRECATED CountTitle "Please change CountTitle to CountTitleStyle" #-}+{-# DEPRECATED FieldTitle "Please change FieldTitle to FieldTitleStyle" #-}+{-# DEPRECATED Legend "Please change Legend to LegendStyle" #-}+{-# DEPRECATED NumberFormat "Please change NumberFormat to NumberFormatStyle" #-}+{-# DEPRECATED Padding "Please change Padding to PaddingStyle" #-}+{-# DEPRECATED Projection "Please change Projection to ProjectionStyle" #-}+{-# DEPRECATED Range "Please change Range to RangeStyle" #-}+{-# DEPRECATED Scale "Please change Scale to ScaleStyle" #-}+{-# DEPRECATED TimeFormat "Please change TimeFormat to TimeFormatStyle" #-}+{-# DEPRECATED View "Please change View to ViewStyle" #-} +{-# DEPRECATED NamedStyle "Please change Legend to MarkNamedStyles" #-}+{-# DEPRECATED NamedStyles "Please change Legend to MarkNamedStyles" #-}+ data ConfigurationProperty     = AreaStyle [MarkProperty]       -- ^ The default appearance of area marks.-    | Autosize [Autosize]+    | AutosizeStyle [Autosize]       -- ^ The default sizing of visualizations.+      --+      --   This was renamed from @Autosize@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0     | Axis [AxisConfig]       -- ^ The default appearance of axes.     | AxisBand [AxisConfig]       -- ^ The default appearance of axes with band scaling.+      --+      --   See also 'AxisDiscrete'.     | AxisBottom [AxisConfig]       -- ^ The default appearance of the bottom-side axes.+    | AxisDiscrete [AxisConfig]+      -- ^ The default appearance of axes with point or band scales.+      --+      --   See also 'AxisBand' and 'AxisPoint'.+      --+      --   @since 0.6.0.0     | AxisLeft [AxisConfig]       -- ^ The default appearance of the left-side axes.+    | AxisPoint [AxisConfig]+      -- ^ The default appearance of axes with point scales.+      --+      --   See also 'AxisDiscrete'.+      --+      --   @since 0.6.0.0+    | AxisQuantitative [AxisConfig]+      -- ^ The default appearance of quantitative axes.+      --+      --   @since 0.6.0.0     | AxisRight [AxisConfig]       -- ^ The default appearance of the right-side axes.+    | AxisTemporal [AxisConfig]+      -- ^ The default appearance of temporal axes.+      --+      --   @since 0.6.0.0     | AxisTop [AxisConfig]       -- ^ The default appearance of the top-side axes.     | AxisX [AxisConfig]       -- ^ The default appearance of the X axes.     | AxisY [AxisConfig]       -- ^ The default appearance of the Y axes.-    | Background Color+    | AxisNamedStyles [(StyleLabel, [AxisProperty])]+      -- ^  Assign a set of axis styles to a label. These labels can then be referred+      --    to when configuring an axis with 'Graphics.Vega.VegaLite.AxStyle' and+      --    'AStyle'.+      --+      --   @since 0.6.0.0+    | BackgroundStyle Color       -- ^ The default background color of visualizations.       --       --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+      --+      --   This was renamed from @Background@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0     | BarStyle [MarkProperty]       -- ^ The default appearance of bar marks.+    | BoxplotStyle [MarkProperty]+      -- ^ The default appearance for box plots.+      --+      --   @since 0.6.0.0     | CircleStyle [MarkProperty]       -- ^ The default appearance of circle marks.-    | ConcatStyle [ConcatConfig]+    | ConcatStyle [CompositionConfig]       -- ^ The default appearance of concatenated layouts.       --+      --   In @0.6.0.0@ this was changed from accepting @ConcatConfig@ to+      --   'CompositionConfig'.+      --       --   @since 0.4.0.0-    | CountTitle T.Text-      -- ^ The default title style for count fields.-    | FacetStyle [FacetConfig]+    | CountTitleStyle T.Text+      -- ^ The default axis and legend title for count fields. The default is+      --   @"Count of Records"@.+      --+      --   This was renamed from @CountTitle@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0+    | ErrorBandStyle [MarkProperty]+      -- ^ The default appearance for error bands.+      --+      --   @since 0.6.0.0+    | ErrorBarStyle [MarkProperty]+      -- ^ The default appearance for error bars.+      --+      --   @since 0.6.0.0+    | FacetStyle [CompositionConfig]       -- ^ The default appearance of facet layouts.       --+      --   In @0.6.0.0@ this was changed from accepting @FacetConfig@ to+      --   'CompositionConfig'.+      --       --   @since 0.4.0.0-    | FieldTitle FieldTitleProperty+    | FieldTitleStyle FieldTitleProperty       -- ^ The default title-generation style for fields.+      --+      --   This was renamed from @FieldTitle@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0+    | FontStyle T.Text+      -- ^ The default font for all text marks, titles, and labels.+      --+      --   The naming scheme used here is somewhat unfortunate, as this+      --   is for the name of the font (such as @\"serif\"@ or+      --   @\"Comic Sans MS\"@), not the font-style.+      --+      --   @since 0.6.0.0     | GeoshapeStyle [MarkProperty]       -- ^ The default appearance of geoshape marks.       --       --   @since 0.4.0.0     | HeaderStyle [HeaderProperty]-      -- ^ The default appearance of facet headers.+      -- ^ The default appearance of all headers.       --       --   @since 0.4.0.0-    | Legend [LegendConfig]+    | HeaderColumnStyle [HeaderProperty]+      -- ^ The default appearance for column headers.+      --+      --   @since 0.6.0.0+    | HeaderFacetStyle [HeaderProperty]+      -- ^ The default appearance for non-row and non-column facet headers.+      --+      --   @since 0.6.0.0+    | HeaderRowStyle [HeaderProperty]+      -- ^ The default appearance for row headers.+      --+      --   @since 0.6.0.0+    | ImageStyle [MarkProperty]+      -- ^ The default appearance for images.+      --+      --   @since 0.6.0.0+    | LegendStyle [LegendConfig]       -- ^ The default appearance of legends.+      --+      --   This was renamed from @Legend@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0     | LineStyle [MarkProperty]       -- ^ The default appearance of line marks.     | MarkStyle [MarkProperty]       -- ^ The default mark appearance.-    | NamedStyle T.Text [MarkProperty]-      -- ^ The default appearance of a single named style.-    | NamedStyles [(T.Text, [MarkProperty])]-      -- ^ The default appearance of a list of named styles.+    | MarkNamedStyles [(StyleLabel, [MarkProperty])]+      -- ^  Assign a set of mark styles to a label. These labels can then be referred+      --    to when configuring a mark, such as with 'TStyle'.       ---      --   @since 0.4.0.0-    | NumberFormat T.Text-      -- ^ The default number formatting for axis and text labels.-    | Padding Padding+      --   @since 0.6.0.0+    | NumberFormatStyle T.Text+      -- ^ The default number formatting for axis and text labels, using+      --   [D3's number format pattern](https://github.com/d3/d3-format#locale_format).+      --+      --   As an example @NumberFormatStyle "s"@ will use SI units.+      --+      --   This was renamed from @NumberFormat@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0+    | PaddingStyle Padding       -- ^ The default padding in pixels from the edge of the of visualization       --   to the data rectangle.+      --+      --   This was renamed from @Padding@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0     | PointStyle [MarkProperty]       -- ^ The default appearance of point marks.-    | Projection [ProjectionProperty]+    | ProjectionStyle [ProjectionProperty]       -- ^ The default style of map projections.-    | Range [RangeConfig]+      --+      --   This was renamed from @Projection@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0+    | RangeStyle [RangeConfig]       -- ^ The default range properties used when scaling.+      --+      --   This was renamed from @Range@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0     | RectStyle [MarkProperty]       -- ^ The default appearance of rectangle marks.+    | RepeatStyle [CompositionConfig]+      -- ^ The default appearance for the 'Graphics.Vega.VegaLite.repeat` operator.+      --+      --   @since 0.6.0.0     | RuleStyle [MarkProperty]       -- ^ The default appearance of rule marks.-    | Scale [ScaleConfig]   -- TODO: rename ScaleStyle+    | ScaleStyle [ScaleConfig]       -- ^ The default properties used when scaling.+      --+      --   This was renamed from @Scale@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0     | SelectionStyle [(Selection, [SelectionProperty])]       -- ^ The default appearance of selection marks.     | SquareStyle [MarkProperty]@@ -244,69 +382,170 @@       -- ^ The default appearance of text marks.     | TickStyle [MarkProperty]       -- ^ The default appearance of tick marks.-    | TimeFormat T.Text-      -- ^ The default time format for axis and legend labels.+    | TimeFormatStyle T.Text+      -- ^ The default time format for raw time values (without time units)+      --   in text marks, legend labels, and header labels. This does /not/+      --   control the appearance of axis labels.+      --+      --   The default is @\"%b %d, %Y\"@.+      --+      --   This was renamed from @TimeFormat@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0     | TitleStyle [TitleConfig]       -- ^ The default appearance of visualization titles.     | TrailStyle [MarkProperty]       -- ^ The default style of trail marks.       --       --   @since 0.4.0.0+    | ViewStyle [ViewConfig]+      -- ^ The default properties for+      --   [single view plots](https://vega.github.io/vega-lite/docs/spec.html#single).+      --+      --   This was renamed from @View@ in @0.6.0.0@.+      --+      --   @since 0.6.0.0+    | Autosize [Autosize]+      -- ^ As of version @0.6.0.0@ this is deprecated and 'AutosizeStyle' should be used+      --   instead.+    | Background Color+      -- ^ As of version @0.6.0.0@ this is deprecated and 'BackgroundStyle' should be used+      --   instead.+    | CountTitle T.Text+      -- ^ As of version @0.6.0.0@ this is deprecated and 'CountTitleStyle' should be used+      --   instead.+    | FieldTitle FieldTitleProperty+      -- ^ As of version @0.6.0.0@ this is deprecated and 'FieldTitleStyle' should be used+      --   instead.+    | Legend [LegendConfig]+      -- ^ As of version @0.6.0.0@ this is deprecated and 'LegendStyle' should be used+      --   instead.+    | NumberFormat T.Text+      -- ^ As of version @0.6.0.0@ this is deprecated and 'NumberFormatStyle' should be used+      --   instead.+    | Padding Padding+      -- ^ As of version @0.6.0.0@ this is deprecated and 'PaddingStyle' should be used+      --   instead.+    | Projection [ProjectionProperty]+      -- ^ As of version @0.6.0.0@ this is deprecated and 'ProjectionStyle' should be used+      --   instead.+    | Range [RangeConfig]+      -- ^ As of version @0.6.0.0@ this is deprecated and 'RangeStyle' should be used+      --   instead.+    | Scale [ScaleConfig]+      -- ^ As of version @0.6.0.0@ this is deprecated and 'ScaleStyle' should be used+      --   instead.+    | TimeFormat T.Text+      -- ^ As of version @0.6.0.0@ this is deprecated and 'TimeFormatStyle' should be used+      --   instead.     | View [ViewConfig]-      -- ^ The default single view style.+      -- ^ As of version @0.6.0.0@ this is deprecated and 'ViewStyle' should be used+      --   instead.+    | NamedStyle StyleLabel [MarkProperty]+      -- ^ As of version @0.6.0.0@ this is deprecated and 'MarkNamedStyles' should be+      --   used instead.+    | NamedStyles [(StyleLabel, [MarkProperty])]+      -- ^ As of version @0.6.0.0@ this is deprecated and 'MarkNamedStyles' should be+      --   used instead. ++toAxis :: T.Text -> [AxisConfig] -> LabelledSpec+toAxis lbl acs = lbl .= object (map axisConfigProperty acs)++aprops_ :: T.Text -> [AxisProperty] -> LabelledSpec+aprops_ f mps = f .= object (map axisProperty mps)+ -- easier to turn into a ConfigSpec in config than here configProperty :: ConfigurationProperty -> LabelledSpec-configProperty (Autosize aus) = "autosize" .= object (map autosizeProperty aus)-configProperty (Background bg) = "background" .= bg-configProperty (CountTitle ttl) = "countTitle" .= ttl-configProperty (ConcatStyle cps) = "concat" .= object (map concatConfigProperty cps)-configProperty (FieldTitle ftp) = "fieldTitle" .= fieldTitleLabel ftp-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) = mprops_ "mark" mps-configProperty (Projection pps) = "projection" .= object (map projectionProperty pps) configProperty (AreaStyle mps) = mprops_ "area" mps+configProperty (AutosizeStyle aus) = "autosize" .= object (map autosizeProperty aus)+configProperty (Axis acs) = toAxis "axis" acs+configProperty (AxisBand acs) = toAxis "axisBand" acs+configProperty (AxisBottom acs) = toAxis "axisBottom" acs+configProperty (AxisDiscrete acs) = toAxis "axisDiscrete" acs+configProperty (AxisLeft acs) = toAxis "axisLeft" acs+configProperty (AxisPoint acs) = toAxis "axisPoint" acs+configProperty (AxisQuantitative acs) = toAxis "axisQuantitative" acs+configProperty (AxisRight acs) = toAxis "axisRight" acs+configProperty (AxisTemporal acs) = toAxis "axisTemporal" acs+configProperty (AxisTop acs) = toAxis "axisTop" acs+configProperty (AxisX acs) = toAxis "axisX" acs+configProperty (AxisY acs) = toAxis "axisY" acs++-- configProperty (AxisNamedStyles [(nme, mps)]) = "style" .= object [aprops_ nme mps]+configProperty (AxisNamedStyles styles) =+  let toStyle = uncurry aprops_+  in "style" .= object (map toStyle styles)++configProperty (BackgroundStyle bg) = "background" .= bg configProperty (BarStyle mps) = mprops_ "bar" mps+configProperty (BoxplotStyle mps) = mprops_ "boxplot" mps configProperty (CircleStyle mps) = mprops_ "circle" mps-configProperty (FacetStyle fps) = "facet" .= object (map facetConfigProperty fps)+configProperty (ConcatStyle cps) = "concat" .= object (map compConfigProperty cps)+configProperty (CountTitleStyle ttl) = "countTitle" .= ttl+configProperty (ErrorBandStyle mps) = mprops_ "errorband" mps+configProperty (ErrorBarStyle mps) = mprops_ "errorbar" mps+configProperty (FacetStyle cps) = "facet" .= object (map compConfigProperty cps)+configProperty (FieldTitleStyle ftp) = "fieldTitle" .= fieldTitleLabel ftp+configProperty (FontStyle font) = "font" .= font configProperty (GeoshapeStyle mps) = mprops_ "geoshape" mps-configProperty (HeaderStyle hps) = header_ hps+configProperty (HeaderStyle hps) = header_ "" hps+configProperty (HeaderColumnStyle hps) = header_ "Column" hps+configProperty (HeaderFacetStyle hps) = header_ "Facet" hps+configProperty (HeaderRowStyle hps) = header_ "Row" hps+configProperty (ImageStyle mps) = mprops_ "image" mps+configProperty (LegendStyle lcs) = "legend" .= object (map legendConfigProperty lcs) configProperty (LineStyle mps) = mprops_ "line" mps++configProperty (MarkStyle mps) = mprops_ "mark" mps+-- configProperty (MarkNamedStyles [(nme, mps)]) = "style" .= object [mprops_ nme mps]+configProperty (MarkNamedStyles styles) =+  let toStyle = uncurry mprops_+  in "style" .= object (map toStyle styles)++configProperty (NumberFormatStyle fmt) = "numberFormat" .= fmt+configProperty (PaddingStyle pad) = "padding" .= paddingSpec pad configProperty (PointStyle mps) = mprops_ "point" mps+configProperty (ProjectionStyle pps) = "projection" .= object (map projectionProperty pps)+configProperty (RangeStyle rcs) = "range" .= object (map rangeConfigProperty rcs) configProperty (RectStyle mps) = mprops_ "rect" mps+configProperty (RepeatStyle cps) = "repeat" .= object (map compConfigProperty cps) configProperty (RuleStyle mps) = mprops_ "rule" mps+configProperty (ScaleStyle scs) = scaleConfig_ scs+configProperty (SelectionStyle selConfig) =+  let selProp (sel, sps) = selectionLabel sel .= object (concatMap selectionProperties sps)+  in "selection" .= object (map selProp selConfig) configProperty (SquareStyle mps) = mprops_ "square" mps configProperty (TextStyle mps) = mprops_ "text" mps configProperty (TickStyle mps) = mprops_ "tick" mps+configProperty (TimeFormatStyle fmt) = "timeFormat" .= fmt configProperty (TitleStyle tcs) = "title" .= object (map titleConfigSpec tcs)+configProperty (TrailStyle mps) = mprops_ "trail" mps+configProperty (ViewStyle vcs) = "view" .= object (concatMap viewConfigProperties vcs)++-- deprecated aliases+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 (Legend lcs) = "legend" .= object (map legendConfigProperty lcs)+configProperty (NumberFormat fmt) = "numberFormat" .= fmt+configProperty (Padding pad) = "padding" .= paddingSpec pad+configProperty (Projection pps) = "projection" .= object (map projectionProperty pps)+configProperty (Range rcs) = "range" .= object (map rangeConfigProperty rcs)+configProperty (Scale scs) = scaleConfig_ scs+configProperty (TimeFormat fmt) = "timeFormat" .= fmt+configProperty (View vcs) = "view" .= object (concatMap viewConfigProperties vcs)+ configProperty (NamedStyle nme mps) = "style" .= object [mprops_ nme mps] configProperty (NamedStyles styles) =   let toStyle = uncurry mprops_   in "style" .= object (map toStyle styles)-configProperty (Scale scs) = scaleConfig_ scs-configProperty (Range rcs) = "range" .= object (map rangeConfigProperty rcs)-configProperty (SelectionStyle selConfig) =-  let selProp (sel, sps) = selectionLabel sel .= object (concatMap selectionProperties sps)-  in "selection" .= object (map selProp selConfig)-configProperty (TrailStyle mps) = mprops_ "trail" mps-configProperty (View vcs) = "view" .= object (concatMap viewConfigProperties vcs) - {-| -Scale configuration property. These are used to configure all scales.-For more details see the+Scale configuration property. These are used to configure all scales+with 'ScaleStyle'. For more details see the <https://vega.github.io/vega-lite/docs/scale.html#scale-config Vega-Lite documentation>.  Version @0.5.0.0@ removed the @SCRangeStep@ and @SCTextXRangeStep@@@ -369,7 +608,10 @@       --   for snapping to the pixel grid.     | SCUseUnaggregatedDomain Bool       -- ^ Whether or not to use the source data range before aggregation.-+    | SCXReverse Bool+      -- ^ Reverse the X scale (useful for right-to-left charts).+      --+      --   @since 0.6.0.0  scaleConfig_ :: [ScaleConfig] -> LabelledSpec -- scaleConfig_ [] = "scale" .= A.Null  -- not sure here@@ -395,10 +637,16 @@  {-| -Legend configuration options, set with the 'Legend' constructor.+Legend configuration options, set with the 'LegendStyle' constructor. For more detail see the <https://vega.github.io/vega-lite/docs/legend.html#config Vega-Lite documentation>. +In @0.6.0.0@ the following constructors were added (all from Vega-Lite 4.0):+'LeSymbolLimit', 'LeTickCount', 'LeTitleLineHeight', and+'LeUnselectedOpacity'.++In @0.5.0.0@ the @LeShortTimeLabels@ constructor was removed (Vega-Lite 4.0).+ This data type has seen significant changes in the @0.4.0.0@ release:  - the @EntryPadding@, @GradientHeight@, @GradientLabelBaseline@, @GradientWidth@@@ -411,8 +659,6 @@  - and new constructors were added. -In @0.5.0.0@ the @LeShortTimeLabels@ constructor was removed.- -}  -- based on schema 3.3.0 #/definitions/LegendConfig@@ -575,6 +821,11 @@       -- ^ The color of the legend symbol.       --       --   @since 0.4.0.0+    | LeSymbolLimit Int  -- it may be that negative entries allow you to say "drop last 2"+      -- ^ The maximum number of allowed entries for a symbol legend. Any additional entries+      --   will be dropped.+      --+      --   @since 0.6.0.0     | LeSymbolOffset Double       -- ^ The horizontal pixel offset for legend symbols.       --@@ -593,6 +844,10 @@       -- ^ The width of the symbol's stroke.     | LeSymbolType Symbol       -- ^ The default shape type for legend symbols.+    | LeTickCount Int+      -- ^ The desired number of tick values for quantitative legends+      --+      --   @since0.6.0.0     | LeTitle T.Text       -- ^ The legend title.       --@@ -623,6 +878,10 @@       -- ^ The font weight of the legend title.     | LeTitleLimit Double       -- ^ The maxmimum pixel width of the legend title.+    | LeTitleLineHeight Double+      -- ^ The line height, in pixels, for multi-line title text.+      --+      --   @since 0.6.0.0     | LeTitleOpacity Opacity       -- ^ The opacity of the legend title.       --@@ -633,7 +892,12 @@       --   @since 0.4.0.0     | LeTitlePadding Double       -- ^ The padding, in pixels, between title and legend.-+    | LeUnselectedOpacity Opacity+      -- ^ The opacity of unselected legend entries.+      --+      --   The default is 0.35.+      --+      --   @since 0.6.0.0  legendConfigProperty :: LegendConfig -> LabelledSpec legendConfigProperty (LeClipHeight x) = "clipHeight" .= x@@ -683,12 +947,14 @@ legendConfigProperty (LeSymbolDashOffset x) = "symbolDashOffset" .= x legendConfigProperty (LeSymbolDirection o) = "symbolDirection" .= orientationSpec o legendConfigProperty (LeSymbolFillColor s) = "symbolFillColor" .= fromColor s+legendConfigProperty (LeSymbolLimit n) = "symbolLimit" .= n legendConfigProperty (LeSymbolOffset x) = "symbolOffset" .= x legendConfigProperty (LeSymbolOpacity x) = "symbolOpacity" .= x legendConfigProperty (LeSymbolSize x) = "symbolSize" .= x legendConfigProperty (LeSymbolStrokeColor s) = "symbolStrokeColor" .= fromColor s legendConfigProperty (LeSymbolStrokeWidth x) = "symbolStrokeWidth" .= x legendConfigProperty (LeSymbolType s) = "symbolType" .= symbolLabel s+legendConfigProperty (LeTickCount n) = "tickCount" .= n legendConfigProperty (LeTitle s) = "title" .= s legendConfigProperty LeNoTitle = "title" .= A.Null legendConfigProperty (LeTitleAlign ha) = "titleAlign" .= hAlignLabel ha@@ -700,9 +966,11 @@ legendConfigProperty (LeTitleFontStyle s) = "titleFontStyle" .= s legendConfigProperty (LeTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw legendConfigProperty (LeTitleLimit x) = "titleLimit" .= x+legendConfigProperty (LeTitleLineHeight x) = "titleLineHeight" .= x legendConfigProperty (LeTitleOpacity x) = "titleOpacity" .= x legendConfigProperty (LeTitleOrient orient) = "titleOrient" .= sideLabel orient legendConfigProperty (LeTitlePadding x) = "titlePadding" .= x+legendConfigProperty (LeUnselectedOpacity x) = "unselectedOpacity" .= x   {-|@@ -754,15 +1022,21 @@ scaleConfigProperty (SCPointPadding x) = "pointPadding" .= x scaleConfigProperty (SCRound b) = "round" .= b scaleConfigProperty (SCUseUnaggregatedDomain b) = "useUnaggregatedDomain" .= b+scaleConfigProperty (SCXReverse b) = "xReverse" .= b   {-|  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.+view within a visualization (via 'ViewStyle') 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>. +In version @0.6.0.0@ the constructors that used to take an optional color,+namely 'ViewFill' and 'ViewStroke', were split out, so that they+now take a 'Color' argument and new constructors - 'ViewNoFill' and+'ViewNoStroke' - were added to replace the @Nothing@ versions.+ In version @0.5.0.0@ the @ViewWidth@ and @ViewHeight@ constructors have been deprecated, and replaced by 'ViewContinuousWidth', 'ViewContinuousHeight',@@ -803,6 +1077,10 @@       --   The default is @0@.       --       --   @since 0.4.0.0+    | ViewCursor Cursor+      -- ^ The default cursor for single views.+      --+      --   @since 0.6.0.0     | ViewDiscreteWidth Double       -- ^ The default width of single views when the       --   visualization has a discrete x field.@@ -813,10 +1091,15 @@       --   visualization has a discrete y field.       --       --   @since 0.5.0.0-    | ViewFill (Maybe Color)-      -- ^ The fill color.+    | ViewFill Color+      -- ^ The fill color. See also 'ViewNoFill'.       ---      --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+      --   This was changed to use the @Color@ type alias in version @0.5.0.0@+      --   and removed the @Maybe@ type in version @0.6.0.0@.+    | ViewNoFill+      -- ^ Do not use a fill. See also 'ViewFill'.+      --+      --   @since 0.6.0.0     | ViewFillOpacity Opacity       -- ^ The fill opacity.     | ViewOpacity Opacity@@ -834,10 +1117,15 @@       --   'ScaleConfig'.       --       --   @since 0.5.0.0-    | ViewStroke (Maybe Color)-      -- ^ The stroke color.+    | ViewStroke Color+      -- ^ The stroke color. See also 'ViewNoStroke'.       ---      --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+      --   This was changed to use the @Color@ type alias in version @0.5.0.0@+      --   and removed the @Maybe@ type in version @0.6.0.0@.+    | ViewNoStroke+      -- ^ Do not use a stroke color. See also 'ViewStroke'.+      --+      --   @since 0.6.0.0     | ViewStrokeCap StrokeCap       -- ^ The stroke cap for line-ending style.       --@@ -874,13 +1162,16 @@ viewConfigProperties (ViewContinuousWidth x) = ["continuousWidth" .= x] viewConfigProperties (ViewContinuousHeight x) = ["continuousHeight" .= x] viewConfigProperties (ViewCornerRadius x) = ["cornerRadius" .= x]+viewConfigProperties (ViewCursor c) = ["cursor" .= cursorLabel c] viewConfigProperties (ViewDiscreteWidth x) = ["discreteWidth" .= x] viewConfigProperties (ViewDiscreteHeight x) = ["discreteHeight" .= x]-viewConfigProperties (ViewFill ms) = ["fill" .= maybe A.Null fromColor ms]+viewConfigProperties (ViewFill ms) = ["fill" .= fromColor ms]+viewConfigProperties ViewNoFill = ["fill" .= A.Null] viewConfigProperties (ViewFillOpacity x) = ["fillOpacity" .= x] viewConfigProperties (ViewOpacity x) = ["opacity" .= x] viewConfigProperties (ViewStep x) = ["step" .= x]-viewConfigProperties (ViewStroke ms) = ["stroke" .= maybe A.Null fromColor ms]+viewConfigProperties (ViewStroke ms) = ["stroke" .= fromColor ms]+viewConfigProperties ViewNoStroke = ["stroke" .= A.Null] viewConfigProperties (ViewStrokeCap sc) = ["strokeCap" .= strokeCapLabel sc] viewConfigProperties (ViewStrokeDash xs) = ["strokeDash" .= fromDS xs] viewConfigProperties (ViewStrokeDashOffset x) = ["strokeDashOffset" .= x]@@ -898,14 +1189,19 @@  This is used by 'ConfigurationProperty'. +In @0.5.0.0@ the @ShortTimeLabels@ constructor was removed.+ The @TitleMaxLength@ constructor was removed in release @0.4.0.0@. The @TitleLimit@ constructor should be used instead. -In @0.5.0.0@ the @ShortTimeLabels@ constructor was removed.- -} data AxisConfig-    = BandPosition Double+    = AStyle [StyleLabel]+      -- ^ The named styles - generated with 'AxisNamedStyles' - to apply to the+      --   axis or axes.+      --+      --   @since 0.6.0.0+    | BandPosition Double       -- ^ The default axis band position.     | Domain Bool       -- ^ Should the axis domain be displayed?@@ -1015,6 +1311,10 @@       --   @since 0.4.0.0     | LabelLimit Double       -- ^ The maximum width of a label, in pixels.+    | LabelOffset Double+      -- ^ The pixel offset for labels, in addition to 'TickOffset'.+      --+      --   @since 0.6.0.0     | LabelOpacity Opacity       -- ^ The opacity of the label.       --@@ -1067,6 +1367,8 @@     | TickOffset Double       -- ^ The position offset, in pixels, to apply to ticks, labels, and grid lines.       --+      --   See also 'LabelOffset'.+      --       --   @since 0.4.0.0     | TickOpacity Opacity       -- ^ The opacity of the ticks.@@ -1125,6 +1427,9 @@   axisConfigProperty :: AxisConfig -> LabelledSpec+axisConfigProperty (AStyle [s]) = "style" .= s+axisConfigProperty (AStyle s) = "style" .= s+ axisConfigProperty (BandPosition x) = "bandPosition" .= x axisConfigProperty (Domain b) = "domain" .= b axisConfigProperty (DomainColor c) = "domainColor" .= fromColor c@@ -1154,6 +1459,7 @@ axisConfigProperty (LabelFontStyle s) = "labelFontStyle" .= s axisConfigProperty (LabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw axisConfigProperty (LabelLimit x) = "labelLimit" .= x+axisConfigProperty (LabelOffset x) = "labelOffset" .= x axisConfigProperty (LabelOpacity x) = "labelOpacity" .= x axisConfigProperty (LabelOverlap strat) = "labelOverlap" .= overlapStrategyLabel strat axisConfigProperty (LabelPadding pad) = "labelPadding" .= pad@@ -1191,28 +1497,7 @@ axisConfigProperty (TitleY x) = "titleY" .= x axisConfigProperty (TranslateOffset x) = "translate" .= x -{-| -Configuration options for faceted views, used with 'Graphics.Vega.VegaLite.FacetStyle'.--See the-<https://vega.github.io/vega-lite/docs/facet.html#facet-configuration Vega-Lite facet config documentation>.--@since 0.4.0.0---}-data FacetConfig-    = FColumns Int-    -- ^ The maximum number of columns to use in a faceted-flow layout.-    | FSpacing Double-    -- ^ The spacing in pixels between sub-views in a faceted composition.---facetConfigProperty :: FacetConfig -> LabelledSpec-facetConfigProperty (FColumns n) = "columns" .= n-facetConfigProperty (FSpacing x) = "spacing" .= x-- -- | Specifies how the title anchor is positioned relative to the frame. -- --   @since 0.4.0.0@@ -1291,9 +1576,9 @@       -- ^ Default offset, in pixels, of titles relative to the chart body.     | TOrient Side       -- ^ Default placement of titles relative to the chart body.-    | TStyle [T.Text]+    | TStyle [StyleLabel]       -- ^ A list of named styles to apply. A named style can be specified-      --   via 'Graphics.Vega.VegaLite.NamedStyle' or 'Graphics.Vega.VegaLite.NamedStyles'. Later styles in the list will+      --   via 'Graphics.Vega.VegaLite.MarkNamedStyles'. Later styles in the list will       --   override earlier ones if there is a conflict in any of the       --   properties.       --@@ -1358,7 +1643,7 @@ titleConfigSpec (TLineHeight x) = "lineHeight" .= x titleConfigSpec (TOffset x) = "offset" .= x titleConfigSpec (TOrient sd) = "orient" .= sideLabel sd-titleConfigSpec (TStyle [style]) = "style" .= style  -- not really needed+titleConfigSpec (TStyle [style]) = "style" .= style  -- minor simplification titleConfigSpec (TStyle styles) = "style" .= styles titleConfigSpec (TSubtitle s) = "subtitle" .= splitOnNewline s titleConfigSpec (TSubtitleColor s) = "subtitleColor" .= fromColor s@@ -1373,21 +1658,31 @@  {-| -Configuration options for concatenated views, used with 'Graphics.Vega.VegaLite.ConcatStyle'.+Configuration options for composition views, used with+'ConcatStyle', 'FacetStyle', and 'RepeatStyle'. -@since 0.4.0.0+Prior to @0.6.0.0@ this information was made available in+two types - @ConcatConfig@ and @FacetConfig@ - which had+the same meaning. +@since 0.6.0.0+ -}-data ConcatConfig-    = ConcatColumns Int-      -- ^ The maximum number of columns to use in a concatenated flow layout.-    | ConcatSpacing Double-      -- ^ The spacing in pixels between sub-views in a concatenated view.+data CompositionConfig+    = CompColumns Int+      -- ^ The number of columns to use. The default is to use a single+      --   row (an infinite number of columns).+      --+      --   Prior to @0.6.0.0@ this was either @ConcatColumns@ or @FColumns@.+    | CompSpacing Double+      -- ^ The spacing in pixels between sub-views. The default is 20.+      --+      --   Prior to @0.6.0.0@ this was either @ConcatSpacing@ or @FSpacing@.  -concatConfigProperty :: ConcatConfig -> LabelledSpec-concatConfigProperty (ConcatColumns n) = "columns" .= n-concatConfigProperty (ConcatSpacing x) = "spacing" .= x+compConfigProperty :: CompositionConfig -> LabelledSpec+compConfigProperty (CompColumns n) = "columns" .= n+compConfigProperty (CompSpacing x) = "spacing" .= x   {-|
src/Graphics/Vega/VegaLite/Core.hs view
@@ -80,15 +80,16 @@        , AxisProperty(..)        , ConditionalAxisProperty(..) -       , size        , color        , fill-       , stroke-       , strokeWidth-       , opacity        , fillOpacity-       , strokeOpacity+       , opacity        , shape+       , size+       , stroke+       , strokeDash+       , strokeOpacity+       , strokeWidth         , MarkChannel(..) @@ -158,9 +159,10 @@        , configure         -- not for external export-       , schemeProperty        , autosizeProperty+       , axisProperty        , paddingSpec+       , schemeProperty         )     where@@ -194,6 +196,7 @@   , DashOffset   , FieldName   , Opacity+  , StyleLabel   , VegaExpr   , ZIndex   , FontWeight@@ -219,6 +222,7 @@   , CInterpolate   , ViewBackground   , HeaderProperty+  , Symbol   , fromT   , fromColor   , fromDS@@ -249,6 +253,7 @@   , repeatFieldsProperty   , cInterpolateSpec   , viewBackgroundSpec+  , symbolLabel   ) import Graphics.Vega.VegaLite.Input   ( Data@@ -287,9 +292,8 @@ import Graphics.Vega.VegaLite.Time   ( DateTime   , TimeUnit-  , timeUnit_   , dateTimeProperty-  , timeUnitLabel+  , timeUnitSpec   ) import Graphics.Vega.VegaLite.Transform   ( Operation(Count)@@ -335,6 +339,9 @@ mtype_ :: Measurement -> LabelledSpec mtype_ m = "type" .= measurementLabel m +timeUnit_ :: TimeUnit -> LabelledSpec+timeUnit_ tu = "timeUnit" .= timeUnitSpec tu+ -- The assumption at the moment is that it's always correct to -- replace the empty list by null. --@@ -530,6 +537,21 @@       -- ^ Literal string value when encoding with a mark property channel.     | MBoolean Bool       -- ^ Boolean value when encoding with a mark property channel.+    | MSymbol Symbol+      -- ^ A symbol literal. This can be useful when making a symbol dependent on some data or+      --   selection condition (e.g. 'MDataCondition' or 'MSelectionCondition').+      --+      --   For example:+      --+      --   @+      --   'encoding'+      --     . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' "to", 'PmType' 'Graphics.Vega.VegaLite.Quantitative', 'PAxis' [] ]+      --     . 'shape' ['MDataCondition'+      --               [('Expr' "datum.to > 100", [MSymbol 'Graphics.Vega.VegaLite.SymTriangleRight'])]+      --               [MSymbol 'Graphics.Vega.VegaLite.SymTriangleLeft']+      --   @+      --+      --   @since 0.6.0.0  markChannelProperty :: MarkChannel -> [LabelledSpec] markChannelProperty (MName s) = [field_ s]@@ -550,6 +572,7 @@ markChannelProperty (MNumber x) = ["value" .= x] markChannelProperty (MString s) = ["value" .= s] markChannelProperty (MBoolean b) = ["value" .= b]+markChannelProperty (MSymbol s) = ["value" .= symbolLabel s] markChannelProperty (MTitle s) = ["title" .= splitOnNewline s] markChannelProperty MNoTitle = ["title" .= A.Null] @@ -573,7 +596,7 @@ The supported encodings are: 'color', 'column', 'detail', 'fill', 'fillOpacity', 'hyperlink', 'opacity', 'order', 'position', 'row', 'shape', 'size',-'stroke', 'strokeOpacity', 'strokeWidth', 'text', 'tooltip',+'stroke', 'strokeDash', 'strokeOpacity', 'strokeWidth', 'text', 'tooltip', 'tooltips', and 'url'.  There is currently no support for encoding by@@ -700,6 +723,10 @@       --   @since 0.4.0.0     | SDomain ScaleDomain       -- ^ Custom scaling domain.+    | SDomainMid Double+      -- ^ Set the mid-point of a continuous diverging domain.+      --+      --   @since 0.6.0.0     | SExponent Double       -- ^ The exponent to use for power scaling ('Graphics.Vega.VegaLite.ScPow').       --@@ -716,6 +743,10 @@       -- ^ Outer padding to apply to a band scaling.     | SRange ScaleRange       -- ^ Range of a scaling. The type of range depends on the encoding channel.+    | SReverse Bool+      -- ^ Should the order of the scale range be reversed?+      --+      --   @since 0.6.0.0     | SRound Bool       -- ^ Are numeric values in a scaling are rounded to integers?       --@@ -745,6 +776,7 @@ scaleProperty (SClamp b) = "clamp" .= b scaleProperty (SConstant x) = "constant" .= x scaleProperty (SDomain sdType) = "domain" .= scaleDomainSpec sdType+scaleProperty (SDomainMid x) = "domainMid" .= x scaleProperty (SExponent x) = "exponent" .= x scaleProperty (SInterpolate interp) = "interpolate" .= cInterpolateSpec interp scaleProperty (SNice ni) = "nice" .= scaleNiceSpec ni@@ -752,8 +784,10 @@ scaleProperty (SPaddingInner x) = "paddingInner" .= x scaleProperty (SPaddingOuter x) = "paddingOuter" .= x scaleProperty (SRange (RNumbers xs)) = "range" .= xs+scaleProperty (SRange (RNumberLists xss)) = "range" .= xss scaleProperty (SRange (RStrings ss)) = "range" .= ss scaleProperty (SRange (RName s)) = "range" .= s+scaleProperty (SReverse b) = "reverse" .= b scaleProperty (SRound b) = "round" .= b scaleProperty (SScheme nme extent) = schemeProperty nme extent scaleProperty (SZero b) = "zero" .= b@@ -1279,6 +1313,10 @@       -- ^ The maximum width of a label, in pixels.       --       --   @since 0.4.0.0+    | AxLabelOffset Double+      -- ^ The pixel offset for labels, in addition to 'AxTickOffset'.+      --+      --   @since 0.6.0.0     | AxLabelOpacity Opacity       -- ^ The opacity of the label.       --@@ -1306,6 +1344,11 @@       -- ^ The orientation of the axis.     | AxPosition Double       -- ^ The anchor position of the axis in pixels.+    | AxStyle [StyleLabel]+      -- ^ The named styles - generated with 'Graphics.Vega.VegaLite.AxisNamedStyles' -+      --   to apply to the axis.+      --+      --   @since 0.6.0.0     | AxTicks Bool       -- ^ Should tick marks be drawn on an axis?     | AxTickBand BandAlign@@ -1344,6 +1387,8 @@     | AxTickOffset Double       -- ^ The position offset, in pixels, to apply to ticks, labels, and grid lines.       --+      --   See also 'AxLabelOffset'.+      --       --   @since 0.4.0.0     | AxTickOpacity Opacity       -- ^ The opacity of the ticks.@@ -1451,6 +1496,9 @@   axisProperty :: AxisProperty -> LabelledSpec+axisProperty (AxStyle [s]) = "style" .= s+axisProperty (AxStyle s) = "style" .= s+ axisProperty (AxBandPosition x) = "bandPosition" .= x axisProperty (AxDataCondition predicate cap) =   let (ifAxProp, elseAxProp) = conditionalAxisProperty cap@@ -1493,6 +1541,7 @@ axisProperty (AxLabelFontStyle s) = "labelFontStyle" .= s axisProperty (AxLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw axisProperty (AxLabelLimit x) = "labelLimit" .= x+axisProperty (AxLabelOffset x) = "labelOffset" .= x axisProperty (AxLabelOpacity x) = "labelOpacity" .= x axisProperty (AxLabelOverlap s) = "labelOverlap" .= overlapStrategyLabel s axisProperty (AxLabelPadding x) = "labelPadding" .= x@@ -1544,17 +1593,12 @@ which can be conditioned on their position (or label).  The constuctor determines the axis property (a label, tick, or-grid element), the second is the value to set if the condition-is 'True', and the third is the value for when it is 'False'.+grid element), and the two arguments are the value to set if the condition+is 'True' (first), and for when it is 'False' (second).  @since 0.5.0.0 -} --- The 4.0.2 Vega Lite spec does not correctly map the conditional--- label align, so that CAxLabelAlign will generate an invalid JSON--- file. This has been fixed (presumably for 4.0.3); see--- https://github.com/vega/vega-lite/issues/5717- data ConditionalAxisProperty   = CAxGridColor Color Color     -- ^ The color for the axis grid.@@ -1580,8 +1624,16 @@     -- ^ Axis label font style.   | CAxLabelFontWeight FontWeight FontWeight     -- ^ Axis label font weight.+  | CAxLabelOffset Double Double+    -- ^ Axis label offset.+    --+    --  @since 0.6.0.0   | CAxLabelOpacity Opacity Opacity     -- ^ Axis label opacity.+  | CAxLabelPadding Double Double+    -- ^ Axis label padding.+    --+    --   @since 0.6.0.0   | CAxTickColor T.Text T.Text     -- ^ Tick color for the axis.   | CAxTickDash DashStyle DashStyle@@ -1590,8 +1642,12 @@     -- ^ The offset for the dash pattern.   | CAxTickOpacity Opacity Opacity     -- ^ Opacity of the axis tick marks.+  | CAxTickSize Double Double+    -- ^ Size, in pixels, of the axis tick marks.+    --+    --   @since 0.6.0.0   | CAxTickWidth Double Double-    -- ^ Width of the axis tick marks.+    -- ^ Width, in pixels, of the axis tick marks.   conditionalAxisProperty :: ConditionalAxisProperty -> (AxisProperty, AxisProperty)@@ -1607,11 +1663,14 @@ conditionalAxisProperty (CAxLabelFontSize t f) = (AxLabelFontSize t, AxLabelFontSize f) conditionalAxisProperty (CAxLabelFontStyle t f) = (AxLabelFontStyle t, AxLabelFontStyle f) conditionalAxisProperty (CAxLabelFontWeight t f) = (AxLabelFontWeight t, AxLabelFontWeight f)+conditionalAxisProperty (CAxLabelOffset t f) = (AxLabelOffset t, AxLabelOffset f) conditionalAxisProperty (CAxLabelOpacity t f) = (AxLabelOpacity t, AxLabelOpacity f)+conditionalAxisProperty (CAxLabelPadding t f) = (AxLabelPadding t, AxLabelPadding f) conditionalAxisProperty (CAxTickColor t f) = (AxTickColor t, AxTickColor f) conditionalAxisProperty (CAxTickDash t f) = (AxTickDash t, AxTickDash f) conditionalAxisProperty (CAxTickDashOffset t f) = (AxTickDashOffset t, AxTickDashOffset f) conditionalAxisProperty (CAxTickOpacity t f) = (AxTickOpacity t, AxTickOpacity f)+conditionalAxisProperty (CAxTickSize t f) = (AxTickSize t, AxTickSize f) conditionalAxisProperty (CAxTickWidth t f) = (AxTickWidth t, AxTickWidth f)  @@ -2000,7 +2059,9 @@ -}  -- based on schema 3.3.0 #/definitions/FacetFieldDef+-- although it's a bit different now (maybe RowColumnEncodingFieldDef in 4.2.0) + data FacetChannel     = FName FieldName       -- ^ The name of the field from which to pull a data value.@@ -2008,15 +2069,32 @@       -- ^ The encoded field's type of measurement.     | FAggregate Operation       -- ^ Aggregation function for the field.+    | FAlign CompositionAlignment+      -- ^ The alignment to apply to the row- or column- facet's subplot.+      --+      --   @since 0.6.0.0     | FBin [BinProperty]       -- ^ Describe how to bin quantitative fields, or whether the       --   channels are already binned.+    | FCenter Bool+      -- ^ Should sub-views be centered relative to their respective rows or+      --   columns.+      --+      --   @since 0.6.0.0     | FHeader [HeaderProperty]       -- ^ The properties of a facet's header.     | FSort [SortProperty]       -- ^ Sort order for the encoded field.       --       --   @since 0.4.0.0+    | FSpacing Double+      -- ^ The pixel spacing between sub-views.+      --+      --   If you have code from a version of @hvega@ before @0.6.0.0@ that+      --   uses @FSpacing@ (with 'Graphics.Vega.VegaLite.FacetStyle'), please+      --   use 'Graphics.Vega.VegaLite.CompSpacing' as a replacement.+      --+      --   @since 0.6.0.0     | FTimeUnit TimeUnit       -- ^ The time-unit for a temporal field.     | FTitle T.Text@@ -2031,10 +2109,13 @@ facetChannelProperty :: FacetChannel -> LabelledSpec facetChannelProperty (FName s) = field_ s facetChannelProperty (FmType measure) = mtype_ measure+facetChannelProperty (FAlign algn) = "align" .= compositionAlignmentSpec algn facetChannelProperty (FAggregate op) = aggregate_ op facetChannelProperty (FBin bps) = bin bps-facetChannelProperty (FHeader hps) = header_ hps+facetChannelProperty (FCenter b) = "center" .= b+facetChannelProperty (FHeader hps) = header_ "" hps facetChannelProperty (FSort sps) = sort_ sps+facetChannelProperty (FSpacing x) = "spacing" .= x facetChannelProperty (FTitle s) = "title" .= s facetChannelProperty FNoTitle = "title" .= A.Null facetChannelProperty (FTimeUnit tu) = timeUnit_ tu@@ -2227,7 +2308,7 @@ config =     'configure'         . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.Axis' [ 'Graphics.Vega.VegaLite.DomainWidth' 1 ])-        . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.View' [ 'Graphics.Vega.VegaLite.ViewStroke' (Just "transparent") ])+        . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.ViewStyle' [ 'Graphics.Vega.VegaLite.ViewStroke' "transparent" ])         . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.SelectionStyle' [ ( 'Graphics.Vega.VegaLite.Single', [ 'Graphics.Vega.VegaLite.On' \"dblclick\" ] ) ]) @ -}@@ -4402,6 +4483,54 @@  {-| +Encode a stroke-dash channel.++The following will use a different dash style for each value in the+\"symbol" field (a multi-series line chart):++@+'Graphics.Vega.VegaLite.toVegaLite' [ 'Graphics.Vega.VegaLite.dataFromUrl' \"data/stocks.csv\" []+           , 'mark' 'Graphics.Vega.VegaLite.Line' []+           , 'encoding'+             . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"date\", 'PmType' 'Graphics.Vega.VegaLite.Temporal' ]+             . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"price\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+             . strokeDash [ 'MName' \"symbol\", 'MmType' 'Graphics.Vega.VegaLite.Nominal' ]+             $ []+           ]+@++It can also be used to change the line style for connected+points (e.g. to indicate where the data changes its \"predicted\"+value, noting that there are two points at @\"a\"@ equal to @\"E\"@):++@+'Graphics.Vega.VegaLite.toVegaLite' [ 'Graphics.Vega.VegaLite.dataFromColumns' []+             . 'Graphics.Vega.VegaLite.dataColumn' \"a\" ('Strings' [ \"A\", \"B\", \"D\", \"E\", \"E\", \"G\", \"H\"])+             . 'Graphics.Vega.VegaLite.dataColumn' \"b\" ('Numbers' [ 28, 55, 91, 81, 81, 19, 87 ])+             . 'Graphics.Vega.VegaLite.dataColumn' \"predicted\" ('Booleans' [False, False, False, False, True, True, True])+             $ []+           , 'mark' 'Graphics.Vega.VegaLite.Line' []+           , 'encoding'+             . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"a\", 'PmType' 'Graphics.Vega.VegaLite.Ordinal' ]+             . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"b\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+             . strokeDash [ 'MName' \"predicted\", 'MmType' 'Graphics.Vega.VegaLite.Nominal' ]+             $ []+           ]+@++@since 0.6.0.0++-}++strokeDash ::+  [MarkChannel]+  -- ^ What data values are used to control the stoke opacity parameters of the mark.+  -> BuildEncodingSpecs+strokeDash markProps ols = mchan_ "strokeDash" markProps : ols+++{-|+ Encode a stroke opacity channel. This acts in a similar way to encoding by 'opacity' but only affects the exterior boundary of marks. If both 'opacity' and @strokeOpacity@ are specified, @strokeOpacity@ takes precedence for stroke encoding.@@ -4486,7 +4615,7 @@   -- ^ The name of the binned data created by this routine.   -> BuildTransformSpecs timeUnitAs tu field label ols =-  let fields = [ "timeUnit" .= timeUnitLabel tu+  let fields = [ "timeUnit" .= timeUnitSpec tu                , "field" .= field                , "as" .= label ]   in TS (object fields) : ols
src/Graphics/Vega/VegaLite/Foundation.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-}  {-|@@ -7,7 +8,7 @@  Maintainer  : dburke.gw@gmail.com Stability   : unstable-Portability : OverloadedStrings+Portability : CPP, OverloadedStrings  Basic types that are used throughout VegaLite. Would it make sense to break this up into@@ -22,6 +23,7 @@        , DashOffset        , FieldName        , Opacity+       , StyleLabel        , VegaExpr        , ZIndex @@ -118,6 +120,9 @@  import Data.Aeson ((.=), object, toJSON) +#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif  -- added in base 4.8.0.0 / ghc 7.10.1 import Numeric.Natural (Natural)@@ -133,8 +138,8 @@ field_ :: FieldName -> LabelledSpec field_ f = "field" .= f -header_ :: [HeaderProperty] -> LabelledSpec-header_ hps = "header" .= object (map headerProperty hps)+header_ :: T.Text -> [HeaderProperty] -> LabelledSpec+header_ extra hps = ("header" <> extra) .= object (map headerProperty hps)  -- could restrict to ascending/descending order_ :: T.Text -> LabelledSpec@@ -250,6 +255,23 @@  {-| +Convenience type-annotation to indicate a name, or label, that represents+a set of mark or axis styles. The styles are generated with+'Graphics.Vega.VegaLite.AxisNamedStyles' and+'Graphics.Vega.VegaLite.MarkNamedStyles',+and used with constructs such as+'Graphics.Vega.VegaLite.AStyle',+'Graphics.Vega.VegaLite.AxStyle',+'Graphics.Vega.VegaLite.MStyle', and+'Graphics.Vega.VegaLite.TStyle'.++@since 0.6.0.0+-}++type StyleLabel = T.Text++{-|+ Convenience type-annotation label to indicate an angle, which is measured in degrees from the horizontal (so anti-clockwise). @@ -558,21 +580,29 @@  data VAlign     = AlignTop+      -- ^ The position refers to the top of the text.     | AlignMiddle+      -- ^ The middle of the text.     | AlignBottom-+      -- ^ The position refers to the bottom of the text, including+      --   descenders, like g.+    | AlignBaseline+      -- ^ The position refers to the baseline of the text (so it does+      --   not include descenders). This maps to the Vega-Lite+      --   @\"alphabetic\"@ value.+      --+      --   @since 0.6.0.0  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"-+vAlignLabel AlignBaseline = "alphabetic"  {-| @@ -1021,6 +1051,11 @@   -- | Indicates a channel type to be used in a resolution specification.+--+--   Used with the 'Resolve' type and the+--   'Graphics.Vega.VegaLite.BLChannel', 'Graphics.Vega.VegaLite.BLChannelEvent',+--   'Graphics.Vega.VegaLite.ByChannel', and 'Graphics.Vega.VegaLite.Encodings'+--   constructors.  -- assuming this is based on schema 3.3.0 #/definitions/SingleDefUnitChannel @@ -1046,15 +1081,17 @@       -- ^ @since 0.4.0.0     | ChKey       -- ^ @since 0.4.0.0+    | ChOpacity+    | ChShape+    | ChSize     | ChStroke       -- ^ @since 0.3.0.0+    | ChStrokeDash+      -- ^ @since 0.6.0.0     | ChStrokeOpacity       -- ^ @since 0.4.0.0     | ChStrokeWidth       -- ^ @since 0.4.0.0-    | ChOpacity-    | ChShape-    | ChSize     | ChText       -- ^ @since 0.4.0.0     | ChTooltip@@ -1072,17 +1109,18 @@ channelLabel ChLatitude2 = "latitude2" channelLabel ChColor = "color" channelLabel ChFill = "fill"-channelLabel ChStroke = "stroke"-channelLabel ChStrokeWidth = "strokeWidth"+channelLabel ChFillOpacity = "fillOpacity"+channelLabel ChHref = "href"+channelLabel ChKey = "key"+channelLabel ChOpacity = "opacity" channelLabel ChShape = "shape" channelLabel ChSize = "size"-channelLabel ChFillOpacity = "fillOpacity"+channelLabel ChStroke = "stroke"+channelLabel ChStrokeDash = "strokeDash"+channelLabel ChStrokeWidth = "strokeWidth" channelLabel ChStrokeOpacity = "strokeOpacity"-channelLabel ChOpacity = "opacity" channelLabel ChText = "text" channelLabel ChTooltip = "tooltip"-channelLabel ChHref = "href"-channelLabel ChKey = "key"   {-|@@ -1149,7 +1187,9 @@   -- | Specifies the alignment of compositions. It is used with:---   'Graphics.Vega.VegaLite.align', 'Graphics.Vega.VegaLite.alignRC', 'Graphics.Vega.VegaLite.LeGridAlign', and 'Graphics.Vega.VegaLite.LGridAlign'.+--   'Graphics.Vega.VegaLite.align', 'Graphics.Vega.VegaLite.alignRC',+--   'Graphics.Vega.VegaLite.LeGridAlign', 'Graphics.Vega.VegaLite.LGridAlign',+--   and 'Graphics.Vega.VegaLite.FAlign'. -- --   @since 0.4.0.0 @@ -1303,34 +1343,50 @@ cInterpolateSpec (CubeHelixLong gamma) = object [pairT "type" "cubehelix-long", "gamma" .= gamma]  --- | The properties for a single view or layer background.------   Used with 'Graphics.Vega.VegaLite.viewBackground' and---   'Graphics.Vega.VegaLite.ViewBackgroundStyle'.------   @since 0.4.0.0+{-| The properties for a single view or layer background. +Used with 'Graphics.Vega.VegaLite.viewBackground' and+'Graphics.Vega.VegaLite.ViewBackgroundStyle'.++In version @0.6.0.0@ the constructors that used to take an optional color,+namely 'VBFill' and 'VBStroke', were split out, so that they+now take a 'Color' argument and new constructors - 'VBNoFill' and+'VBNoStroke' - were added to replace the @Nothing@ versions.++@since 0.4.0.0++-}+ data ViewBackground-    = VBStyle [T.Text]+    = VBStyle [StyleLabel]     -- ^ A list of named styles to apply. A named style can be specified-    --   via 'Graphics.Vega.VegaLite.NamedStyle' or 'Graphics.Vega.VegaLite.NamedStyles'. Later styles in the list will+    --   via 'Graphics.Vega.VegaLite.MarkNamedStyles'. Later styles in the list will     --   override earlier ones if there is a conflict in any of the mark     --   properties.     | VBCornerRadius Double     -- ^ The radius in pixels of rounded corners.-    | VBFill (Maybe Color)-    -- ^ Fill color.+    | VBFill Color+    -- ^ Fill color. See also 'VBNoFill'.     ---    --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    --   This was changed to use the @Color@ type alias in version @0.5.0.0@+    --   and removed the @Maybe@ type in version @0.6.0.0@.+    | VBNoFill+    -- ^ Do not use a fill. See also 'VBFill'.+    --+    --   @since 0.6.0.0     | VBFillOpacity Opacity     -- ^ Fill opacity.     | VBOpacity Opacity     -- ^ Overall opacity.-    | VBStroke (Maybe Color)-    -- ^ The stroke color for a line around the background. If @Nothing@ then-    --   no line is drawn.+    | VBStroke Color+    -- ^ The stroke color for a line around the background. See also 'VBNoStroke'.     ---    --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    --   This was changed to use the @Color@ type alias in version @0.5.0.0@+    --   and removed the @Maybe@ type in version @0.6.0.0@.+    | VBNoStroke+    -- ^ Do not use a stroke. See also 'VBStroke'.+    --+    --   @since 0.6.0.0     | VBStrokeOpacity Opacity     -- ^ The opacity of the line around the background, if drawn.     | VBStrokeWidth Double@@ -1351,12 +1407,12 @@ viewBackgroundSpec (VBStyle [style]) = "style" .= style  -- special case singleton viewBackgroundSpec (VBStyle styles) = "style" .= styles viewBackgroundSpec (VBCornerRadius r) = "cornerRadius" .= r-viewBackgroundSpec (VBFill (Just s)) = "fill" .= s-viewBackgroundSpec (VBFill Nothing) = "fill" .= A.Null+viewBackgroundSpec (VBFill s) = "fill" .= s+viewBackgroundSpec VBNoFill = "fill" .= A.Null viewBackgroundSpec (VBFillOpacity x) = "fillOpacity" .= x viewBackgroundSpec (VBOpacity x) = "opacity" .= x-viewBackgroundSpec (VBStroke (Just s)) = "stroke" .= s-viewBackgroundSpec (VBStroke Nothing) = "stroke" .= A.Null+viewBackgroundSpec (VBStroke s) = "stroke" .= s+viewBackgroundSpec VBNoStroke = "stroke" .= A.Null viewBackgroundSpec (VBStrokeOpacity x) = "strokeOpacity" .= x viewBackgroundSpec (VBStrokeCap cap) = "strokeCap" .= strokeCapLabel cap viewBackgroundSpec (VBStrokeJoin jn) = "strokeJoin" .= strokeJoinLabel jn@@ -1376,9 +1432,16 @@  -} --- TODO: should there be a HLabelBaseline, HTitleFontStyle, ...?---       However, the following covers the vega-lite 3.3.0 schema+{-+In 4.2.0 this represents both +  HeaderConfig+  Header++which have the same keys.++-}+ data HeaderProperty     = HFormat T.Text       -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html) for@@ -1396,12 +1459,10 @@       --   with 'HFormat'.       --       -- @since 0.4.0.0-    | HTitle T.Text-      -- ^ The title for the facets.-    | HNoTitle-      -- ^ Draw no title for the facets.+    | HLabel Bool+      -- ^ Should labels be included as part of the header. The default is @True@.       ---      -- @since 0.4.0.0+      --   @since 0.6.0.0     | HLabelAlign HAlign       -- ^ The horizontal alignment of the labels.       --@@ -1411,13 +1472,21 @@       --       -- @since 0.4.0.0     | HLabelAngle Angle-      -- ^ The angle to draw the labels.+      -- ^ The angle to draw the labels. The default is 0 for column headers+      --   and -90 for row headers.       ---      -- @since 0.4.0.0+      --   @since 0.4.0.0     | HLabelColor Color       -- ^ The color of the labels.       --       -- @since 0.4.0.0+    | HLabelExpr VegaExpr+      -- ^ The expression used to generate header labels.+      --+      --   The expression can use @datum.value@ and @datum.label@ to access+      --   the data value and default label text respectively.+      --+      --   @since 0.6.0.0     | HLabelFont T.Text       -- ^ The font for the labels.       --@@ -1426,6 +1495,10 @@       -- ^ The font size for the labels.       --       -- @since 0.4.0.0+    | HLabelFontStyle T.Text+      -- ^ The font style for the labels.+      --+      --   @since 0.6.0.0     | HLabelLimit Double       -- ^ The maximum length of each label.       --@@ -1438,6 +1511,12 @@       -- ^ The spacing in pixels between the label and its sub-plot.       --       -- @since 0.4.0.0+    | HTitle T.Text+      -- ^ The title for the facets.+    | HNoTitle+      -- ^ Draw no title for the facets.+      --+      -- @since 0.4.0.0     | HTitleAlign HAlign       -- ^ The horizontal alignment of the title.       --@@ -1466,6 +1545,10 @@       -- ^ The font size for the title.       --       -- @since 0.4.0.0+    | HTitleFontStyle T.Text+      -- ^ The font style for the title.+      --+      --   @since 0.6.0.0     | HTitleFontWeight T.Text       -- ^ The font weight for the title.       --@@ -1474,6 +1557,10 @@       -- ^ The maximum length of the title.       --       -- @since 0.4.0.0+    | HTitleLineHeight Double+      -- ^ The line height, in pixels, for multi-line title text.+      --+      --   @since 0.6.0.0     | HTitleOrient Side       -- ^ The position of the title relative to the sub-plots.       --@@ -1490,12 +1577,15 @@ headerProperty HFormatAsTemporal = "formatType" .= fromT "time" headerProperty (HTitle ttl) = "title" .= splitOnNewline ttl headerProperty HNoTitle = "title" .= A.Null+headerProperty (HLabel b) = "labels" .= b headerProperty (HLabelAlign ha) = "labelAlign" .= hAlignLabel ha headerProperty (HLabelAnchor a) = "labelAnchor" .= anchorLabel a headerProperty (HLabelAngle x) = "labelAngle" .= x headerProperty (HLabelColor s) = "labelColor" .= fromColor s+headerProperty (HLabelExpr s) = "labelExpr" .= s headerProperty (HLabelFont s) = "labelFont" .= s headerProperty (HLabelFontSize x) = "labelFontSize" .= x+headerProperty (HLabelFontStyle s) = "labelFontStyle" .= s headerProperty (HLabelLimit x) = "labelLimit" .= x headerProperty (HLabelOrient orient) = "labelOrient" .= sideLabel orient headerProperty (HLabelPadding x) = "labelPadding" .= x@@ -1507,6 +1597,8 @@ headerProperty (HTitleFont s) = "titleFont" .= s headerProperty (HTitleFontWeight s) = "titleFontWeight" .= s headerProperty (HTitleFontSize x) = "titleFontSize" .= x+headerProperty (HTitleFontStyle s) = "titleFontStyle" .= s headerProperty (HTitleLimit x) = "titleLimit" .= x+headerProperty (HTitleLineHeight x) = "titleLineHeight" .= x headerProperty (HTitleOrient orient) = "titleOrient" .= sideLabel orient headerProperty (HTitlePadding x) = "titlePadding" .= x
src/Graphics/Vega/VegaLite/Mark.hs view
@@ -50,6 +50,7 @@   , Cursor   , FontWeight   , Opacity+  , StyleLabel   , Orientation   , StrokeCap   , StrokeJoin@@ -75,8 +76,9 @@   )  --- TODO: should this turn an empty list into true?+-- As of version 0.6.0.0, an empty list is mapped to True mprops_ :: T.Text -> [MarkProperty] -> LabelledSpec+mprops_ f [] = f .= True mprops_ f mps = f .= object (map markProperty mps)  @@ -203,9 +205,9 @@  Not all properties are valid for each mark type. -The Vega-Lite specification supports setting those properties that take-@['MarkProperty']@ also to a boolean value. This is currently not-supported in @hvega@.+Some properties which take a list - such as 'MBox' - will+create a @true@ value if the list is empty, and @false@ if the+@\"No\"@ variant of the constructor is used (e.g. 'MNoBox').  In @version 0.5.0.0@ the 'MRemoveInvalid' constructor was added, which replaces the @RemoveInvalid@ constructor of@@ -242,13 +244,21 @@       --   The ideal value for this is either @0@ (preferred by statisticians)       --   or @1@ (the Vega-Lite default value, D3 example style).     | MBorders [MarkProperty]-      -- ^ Border properties for an 'ErrorBand' mark.+      -- ^ Border properties for an 'ErrorBand' mark. See also 'MNoBorders'.       --       --   @since 0.4.0.0+    | MNoBorders+      -- ^ Do not draw a border for an 'ErrorBand' mark.+      --+      --   @since 0.6.0.0     | MBox [MarkProperty]-      -- ^ Box-symbol properties for a 'Boxplot' mark.+      -- ^ Box-symbol properties for a 'Boxplot' mark. See also 'MNoBox'.       --       --   @since 0.4.0.0+    | MNoBox+      -- ^ Do not draw outliers with the 'Boxplot' mark.+      --+      --   @since 0.6.0.0     | MClip Bool       -- ^ Should a mark be clipped to the enclosing group's dimensions.     | MColor Color@@ -276,6 +286,15 @@       --   or 'MCornerRadiusBR'.       --       --   @since 0.5.0.0+    | MCornerRadiusEnd Double+      -- ^ The radius used for bars, in pixels. For vertical bars it+      --   defines the top-left and top-right radius, and for+      --   horizontal bars it is the top-right and bottom-right.+      --+      --   For an example, see the+      --   <https://vega.github.io/vega-lite/docs/bar.html#bar-chart-with-rounded-corners Vega-Lite documentation>.+      --+      --   @since 0.6.0.0     | MCornerRadiusTL Double       -- ^ Top-left corner radius of a rectangular mark, in pixels.       --@@ -398,9 +417,13 @@       --       --   @since 0.5.0.0     | MMedian [MarkProperty]-      -- ^ Median-line properties for the 'Boxplot' mark.+      -- ^ Median-line properties for the 'Boxplot' mark. See also 'MNoMedian'.       --       --   @since 0.4.0.0+    | MNoMedian+      -- ^ Do not draw the median of the 'Boxplot' mark.+      --+      --   @since 0.6.0.0     | MOpacity Opacity       -- ^ Overall opacity of a mark in the range 0 to 1.     | MOrder Bool@@ -412,7 +435,7 @@     | MOrient Orientation       -- ^ Orientation of a non-stacked bar, tick, area or line mark.     | MOutliers [MarkProperty]-      -- ^ Outlier symbol properties for the 'Boxplot' mark.+      -- ^ Outlier symbol properties for the 'Boxplot' mark. See also 'MNoOutliers'.       --       --   @since 0.4.0.0     | MNoOutliers@@ -436,9 +459,13 @@       --       --   @since 0.5.0.0     | MRule [MarkProperty]-      -- ^ Rule (main line) properties for the 'ErrorBar' and 'Boxplot' marks.+      -- ^ Rule (main line) properties for the 'ErrorBar' and 'Boxplot' marks. See also 'MNoRule'.       --       --   @since 0.4.0.0+    | MNoRule+      -- ^ Do not draw the rule for 'ErrorBar' and 'Boxplot' marks.+      --+      --   @since 0.6.0.0     | MShape Symbol       -- ^ Shape of a point mark.     | MSize Double@@ -482,13 +509,22 @@       -- ^ Stroke opacity of a mark in the range 0 to 1.     | MStrokeWidth Double       -- ^ Stroke width of a mark in pixels.-    | MStyle [T.Text]+    | MStyle [StyleLabel]       -- ^ Names of custom styles to apply to a mark. Each should refer to a named style-      --   defined in a separate style configuration.+      --   defined in a separate style configuration (using+      --   'Graphics.Vega.VegaLite.MarkNamedStyles').     | MTension Double       -- ^ Interpolation tension used when interpolating line and area marks.     | MText T.Text       -- ^ Placeholder text for a text mark for when a text channel is not specified.+      --+      --   See 'MTexts' for supplying an array of text values.+    | MTexts [T.Text]+      -- ^ Placeholder text for a text mark for when a text channel is not specified.+      --+      --   See 'MText' for supplying a single text value.+      --+      --   @since 0.6.0.0     | MTheta Double       -- ^ Polar coordinate angle (clockwise from north in radians)       --   of a text mark from the origin (determined by its@@ -496,9 +532,18 @@     | MThickness Double       -- ^ Thickness of a tick mark.     | MTicks [MarkProperty]-      -- ^ Tick properties for the 'ErrorBar' or 'Boxplot' mark.+      -- ^ Tick properties for the 'ErrorBar' or 'Boxplot' mark. See also 'MNoTicks'.       --       --   @since 0.4.0.0+    | MNoTicks+      -- ^ Do not draw ticks for 'ErrorBar' or 'Boxplot' marks.+      --+      --   The default behavior for ticks is for them to not be drawn, so @MNoTicks@+      --   is only needed if the visualization contains something like:+      --+      --   @'Graphics.Vega.VegaLite.configure' ('Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.BoxplotStyle' ['MTicks' []] []))@+      --+      --   @since 0.6.0.0     | MTimeUnitBand Double       -- ^ The default relative band size for a time unit.       --@@ -517,14 +562,6 @@       -- ^ The tooltip content for a mark.       --       --   @since 0.4.0.0-      {- Not clear this adds anything with the current hvega design,-         since the mark function adds this field, and other places that-         MarkProperty can be used do not accept a type option-    | MType Mark-      -- ^ The mark type.-      ---      --   @since 0.5.0.0-       -}     | MWidth Double       -- ^ Explicitly set the width of a mark (e.g. the bar width). See also       --   'MHeight'.@@ -591,14 +628,17 @@ markProperty (MBinSpacing x) = "binSpacing" .= x  -- only available in ErrorBand[Config|Def], PartsMixins<ErrorBandPart>+markProperty MNoBorders = "borders" .= False markProperty (MBorders mps) = mprops_ "borders" mps  -- BoxPlot[Config|Deg], PartsMixins<BoxPlotPart>+markProperty MNoBox = "box" .= False markProperty (MBox mps) = mprops_ "box" mps  markProperty (MClip b) = "clip" .= b markProperty (MColor col) = "color" .= fromColor col markProperty (MCornerRadius x) = "cornerRadius" .= x+markProperty (MCornerRadiusEnd x) = "cornerRadiusEnd" .= x markProperty (MCornerRadiusTL x) = "cornerRadiusTopLeft" .= x markProperty (MCornerRadiusTR x) = "cornerRadiusTopRight" .= x markProperty (MCornerRadiusBL x) = "cornerRadiusBottomLeft" .= x@@ -629,6 +669,7 @@ markProperty (MLineHeight x) = "lineHeight" .= x  -- BoxPlot[Config|Def] possibly others+markProperty MNoMedian = "median" .= False markProperty (MMedian mps) = mprops_ "median" mps  markProperty (MOpacity x) = "opacity" .= x@@ -636,14 +677,14 @@ markProperty (MOrient orient) = "orient" .= orientationSpec orient  -- what uses this?-markProperty (MOutliers []) = "outliers" .= True  -- TODO: should mprops_ do this?-markProperty (MOutliers mps) = mprops_ "outliers" mps markProperty MNoOutliers = "outliers" .= False+markProperty (MOutliers mps) = mprops_ "outliers" mps  markProperty (MPoint pm) = "point" .= pointMarkerSpec pm markProperty (MRadius x) = "radius" .= x  -- what uses this?+markProperty MNoRule = "rule" .= False markProperty (MRule mps) = mprops_ "rule" mps  markProperty (MShape sym) = "shape" .= symbolLabel sym@@ -659,20 +700,19 @@ markProperty (MStyle [style]) = "style" .= style  -- special case singleton markProperty (MStyle styles) = "style" .= styles markProperty (MTension x) = "tension" .= x-markProperty (MText txt) = "text" .= txt+markProperty (MText t) = "text" .= t+markProperty (MTexts ts) = "text" .= ts markProperty (MTheta x) = "theta" .= x markProperty (MThickness x) = "thickness" .= x  -- what uses this?+markProperty MNoTicks = "ticks" .= False markProperty (MTicks mps) = mprops_ "ticks" mps  markProperty (MTimeUnitBand x) = "timeUnitBand" .= x markProperty (MTimeUnitBandPosition x) = "timeUnitBandPosition" .= x markProperty (MTooltip TTNone) = "tooltip" .= A.Null markProperty (MTooltip tc) = "tooltip" .= object ["content" .= ttContentLabel tc]-{--markProperty (MType m) = "type" .= markLabel m--} markProperty (MWidth x) = "width" .= x markProperty (MX x) = "x" .= x markProperty (MY x) = "y" .= x
src/Graphics/Vega/VegaLite/Scale.hs view
@@ -2,7 +2,7 @@  {-| Module      : Graphics.Vega.VegaLite.Scale-Copyright   : (c) Douglas Burke, 2018-2019+Copyright   : (c) Douglas Burke, 2018-2020 License     : BSD3  Maintainer  : dburke.gw@gmail.com@@ -38,7 +38,7 @@   ( DateTime   , TimeUnit   , dateTimeProperty-  , timeUnitLabel+  , timeUnitSpec   )  @@ -57,14 +57,29 @@       -- ^ Date-time values that define a scale domain.     | DSelection T.Text       -- ^ Scale domain based on a named interactive selection.+    | DUnionWith ScaleDomain+      -- ^ Combine the domain of the data with the provided domain.+      --+      --   The following example will use a range of at least 0 to 100,+      --   but this will be increased if the data (either initially or+      --   via any updates to the Vege-Lite visualization) exceeds this:+      --+      --   @'Graphics.Vega.VegaLite.PScale' ['Graphics.Vega.VegaLite.SDomain' (DUnionWith ('DNumbers' [0, 100]))]@+      --+      --   Note that 'DUnionWith' should not be nested, but this+      --   is not enforced by @hvega@.+      --+      --   @since 0.6.0.0     | Unaggregated-    -- ^ Specify an unaggregated scale domain (type of data in scale).+    -- ^ Indicate that a domain of aggregated data should be scaled to+    --   the domain of the data prior to aggregation.  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 (DUnionWith sd) = object ["unionWith" .= scaleDomainSpec sd] scaleDomainSpec Unaggregated = "unaggregated"  @@ -108,7 +123,7 @@ scaleNiceSpec NMonth = fromT "month" scaleNiceSpec NYear = fromT "year" scaleNiceSpec (NInterval tu step) =-  object ["interval" .= timeUnitLabel tu, "step" .= step]+  object ["interval" .= timeUnitSpec tu, "step" .= step] scaleNiceSpec (IsNice b) = toJSON b scaleNiceSpec (NTickCount n) = toJSON n @@ -134,8 +149,21 @@       --   a two-element array indicating minimum and maximum values, or an array with more than       --   two entries for specifying a       --   [piecewise scale](https://vega.github.io/vega-lite/docs/scale.html#piecewise).+    | RNumberLists [[Double]]+      -- ^ A scale range comprising of numeric lists, such as custom dash styles for+      --   the 'Graphics.Vega.VegaLite.strokeDash' channel encoding.+      --+      --   @since 0.6.0.0     | RStrings [T.Text]       -- ^ Text scale range for discrete scales.     | RName T.Text       -- ^ Name of a [pre-defined named scale range](https://vega.github.io/vega-lite/docs/scale.html#range-config)       --   (e.g. \"symbol\" or \"diverging\").++{-++TODO:++* TickCount accepts number or TimeInterval but this is a subset of ScaleNice++-}
src/Graphics/Vega/VegaLite/Selection.hs view
@@ -49,10 +49,12 @@   , FieldName   , Opacity   , Channel+  , Cursor   , channelLabel   , fromT   , fromColor   , fromDS+  , cursorLabel   ) import Graphics.Vega.VegaLite.Specification   ( VLProperty(VLSelection)@@ -298,7 +300,12 @@  -} data SelectionMarkProperty-    = SMFill Color+    = SMCursor Cursor+      -- ^ Cursor type to appear when pointer is over an interval selection mark+      --   (dragged rectangular area).+      --+      --   @since 0.6.0.0+    | SMFill Color       -- ^ Fill color.     | SMFillOpacity Opacity       -- ^ Fill opacity.@@ -315,6 +322,7 @@   selectionMarkProperty :: SelectionMarkProperty -> LabelledSpec+selectionMarkProperty (SMCursor c) = "cursor" .= cursorLabel c selectionMarkProperty (SMFill colour) = "fill" .= fromColor colour selectionMarkProperty (SMFillOpacity x) = "fillOpacity" .= x selectionMarkProperty (SMStroke colour) = "stroke" .= fromColor colour
src/Graphics/Vega/VegaLite/Time.hs view
@@ -21,28 +21,23 @@        , TimeUnit(..)         -- not for external export-       , timeUnit_-        , dateTimeProperty-       -- , dayLabel-       -- , monthNameLabel-       , timeUnitLabel+       , timeUnitSpec                ) where  import qualified Data.Text as T -import Data.Aeson ((.=))+import Data.Aeson ((.=), object)  #if !(MIN_VERSION_base(4, 12, 0)) import Data.Monoid ((<>)) #endif -import Graphics.Vega.VegaLite.Specification (LabelledSpec)-+-- added in base 4.8.0.0 / ghc 7.10.1+import Numeric.Natural (Natural) -timeUnit_ :: TimeUnit -> LabelledSpec-timeUnit_ tu = "timeUnit" .= timeUnitLabel tu+import Graphics.Vega.VegaLite.Specification (LabelledSpec, VLSpec)   {-|@@ -127,6 +122,32 @@ @ -} +-- Vega-Lite 4.4.0 has+--   LocalMultiTimeUnit which is yearquarter, yearquartermonth, ,secondsmilliseconds+--   LocalSingleTimeUnit year, quarter, ..., milliseconds+-- and+--   UtcMultiTimeUnit which is utc <> LocalMultiTimeUnit+--   UtcSingleTimeUnit         utc <> LocalSingleTimeUnit+--+-- TimeUnit       is either of SingleTimeUnit or MultiTimeUnit+-- SingleTimeUnut is either of LocalSingleTimeUnit or UtcSingleTimeUnit+-- MultiTimeUnit  is either of LocalMultiTieUnit or UtcMultiTimeUnit+--+-- "timeUnit" settings are TimeUnit or TimeUnitParams+--+-- TimeUnitParams is an object with fields+--   maxbins - number+--   step    - number+--   unit    - this is TimeUnit+--   utc     - boolean+--+-- So, could be something like "TU <time unit type> [options]"+-- where an empty array means it's a "TimeUnit", and the options are from+-- TimeUnitParams (apart from the unit field). Unfortunately this doesn't+-- capture the use case of supplying "maxbins" only (it may be that "step"+-- can also be used without any other value).+--+ data TimeUnit     = Year       -- ^ Year.@@ -175,6 +196,21 @@     | Utc TimeUnit       -- ^ Encode a time as UTC (coordinated universal time, independent of local time       --   zones or daylight saving).+    | TUMaxBins Natural+      -- ^ The maximum number of bins to use when discretising time values.+      --   This can be useful as an algternative to explicitly providing the+      --   time unit to bin by, as it will be inferred from the temporal+      --   extent and the number of bins. As an example, @TUMaxBins 366@+      --   will bin by day when applied to a dataset of hourly readings+      --   for a full year.+      --+      --   @since 0.6.0.0+    | TUStep Double TimeUnit+      -- ^ The number of steps between time-unit bins, in terms of the+      --   least-significant unit provided. So @TUStep 14 YearMonthDate@+      --   wull bin temporal data into bi-weekly groups.+      --+      --   @since 0.6.0.0   dateTimeProperty :: DateTime -> LabelledSpec@@ -216,27 +252,51 @@ 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+-- Assume there's no "embedded" values the time unit used by+-- the "grouping" cases, such as Utc, are "singular" and not+-- themselves compound.+--+-- Ideally this would know when it could just return the label+-- and not a labelled spec, but for now leave it as is.+--+timeHelper :: T.Text -> [LabelledSpec]+timeHelper unit = ["unit" .= unit]++timeUnitProperties :: TimeUnit -> [LabelledSpec]+timeUnitProperties Year = timeHelper "year"+timeUnitProperties YearQuarter = timeHelper "yearquarter"+timeUnitProperties YearQuarterMonth = timeHelper "yearquartermonth"+timeUnitProperties YearMonth = timeHelper "yearmonth"+timeUnitProperties YearMonthDate = timeHelper "yearmonthdate"+timeUnitProperties YearMonthDateHours = timeHelper "yearmonthdatehours"+timeUnitProperties YearMonthDateHoursMinutes = timeHelper "yearmonthdatehoursminutes"+timeUnitProperties YearMonthDateHoursMinutesSeconds = timeHelper "yearmonthdatehoursminutesseconds"+timeUnitProperties Quarter = timeHelper "quarter"+timeUnitProperties QuarterMonth = timeHelper "quartermonth"+timeUnitProperties Month = timeHelper "month"+timeUnitProperties MonthDate = timeHelper "monthdate"+timeUnitProperties Date = timeHelper "date"+timeUnitProperties Day = timeHelper "day"+timeUnitProperties Hours = timeHelper "hours"+timeUnitProperties HoursMinutes = timeHelper "hoursminutes"+timeUnitProperties HoursMinutesSeconds = timeHelper "hoursminutesseconds"+timeUnitProperties Minutes = timeHelper "minutes"+timeUnitProperties MinutesSeconds = timeHelper "minutesseconds"+timeUnitProperties Seconds = timeHelper "seconds"+timeUnitProperties SecondsMilliseconds = timeHelper "secondsmilliseconds"+timeUnitProperties Milliseconds = timeHelper "milliseconds"+timeUnitProperties (Utc tu) = "utc" .= True : timeUnitProperties tu+timeUnitProperties (TUStep x tu) = "step" .= x : timeUnitProperties tu+timeUnitProperties (TUMaxBins n) = [ "maxbins" .= n ]+++-- Special case this so that+--   {'unit': blah}              -> blah+--   {'unit': blah, 'utc': true} -> 'utc' <> blah  [would be nice but not done for now]+--+timeUnitSpec :: TimeUnit -> VLSpec+timeUnitSpec tu =+  let props = timeUnitProperties tu+  in case props of+    [(k, v)] | k == "unit" -> v+    _ -> object props
stack.yaml view
@@ -5,4 +5,4 @@  extra-deps: [] -resolver: lts-14.23+resolver: lts-15.0
tests/AxisTests.hs view
@@ -13,19 +13,31 @@  testSpecs :: [(String, VegaLite)] testSpecs = [ ("axis1", axis1)+            , ("axis1c", axis1c)             , ("axis2", axis2)+            , ("axis2c", axis2c)             , ("axis3", axis3)+            , ("axis3c", axis3c)             , ("axis4", axis4)+            , ("axis4c", axis4c)             , ("axis5", axis5)+            , ("axis5c", axis5c)             , ("axis6", axis6)+            , ("axis6c", axis6c)             , ("axis7", axis7)+            , ("axis7c", axis7c)             , ("axis8", axis8)+            , ("axis8c", axis8c)             , ("axisOverlapNone", axisOverlapNone)             , ("axisOverlapParity", axisOverlapParity)             , ("axisOverlapGreedy", axisOverlapGreedy)             , ("zorder", zorder)             , ("responsiveWidth", responsiveWidth)             , ("responsiveHeight", responsiveHeight)+            , ("axisstyleempty", axisStyleEmpty)+            , ("axisstyleemptyx", axisStyleEmptyX)+            , ("axisstylex", axisStyleX)+            , ("axisstylexy", axisStyleXY)             ]  @@ -41,7 +53,7 @@ pName = PName  -simpleData :: [DataColumn] -> Data+simpleData :: Data simpleData =   let xvals = map fromIntegral xs       xs = [1::Int .. 100]@@ -49,9 +61,10 @@        . dataColumn "x" (Numbers xvals)        . dataColumn "catX" (Strings (map (T.pack . show) xs))        . dataColumn "y" (Numbers xvals)+       $ []  -temporalData :: [DataColumn] -> Data+temporalData ::  Data temporalData =   let dates = [ "2019-01-01 09:00:00"               , "2019-01-02 09:00:00"@@ -72,99 +85,99 @@   in dataFromColumns []      . dataColumn "date" (Strings dates)      . dataColumn "y" (Numbers xs)+     $ [] +xQuant, yQuant, catX, xDate :: [PositionChannel]+xQuant = [pName "x", pQuant]+yQuant = [pName "y", pQuant]+catX = [pName "catX", pOrdinal]+xDate = [pName "date", pTemporal] -axis1 :: VegaLite-axis1 =-  let enc = encoding-              . position X [ pName "x", pQuant ]-              . position Y [ pName "y", pQuant ]-    in-    toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ] +axisBase :: Data -> [ConfigurationProperty] -> [PositionChannel] -> [PositionChannel] -> VegaLite+axisBase plotData confOpts xOpts yOpts =+  let enc = encoding . position X xOpts . position Y yOpts -axis2 :: VegaLite-axis2 =-  let enc = encoding-              . position X [ pName "catX", pOrdinal ]-              . position Y [ pName "y", pQuant ]-    in-    toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ]+      conf = case confOpts of+               [] -> []+               _ -> [configure (foldr configuration [] confOpts)]+      vs = conf ++ [ plotData, enc [], mark Line [ MPoint (PMMarker []) ] ] +  in toVegaLite vs -axis3 :: VegaLite-axis3 =-  let enc = encoding-              . position X [ pName "date", pTemporal ]-              . position Y [ pName "y", pQuant ]-    in-    toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ]+plotCfg :: [ConfigurationProperty]+plotCfg = [ AxisQuantitative [ DomainColor "orange"+                             , GridColor "seagreen"+                             , LabelFont "Comic Sans MS"+                             , LabelOffset 10+                             , TickOffset 10+                             ]+          , AxisTemporal [ DomainColor "brown"+                         , DomainDash [4, 2]+                         , Grid False+                         , LabelColor "purple"+                         ]+          , PointStyle [ MStroke "black"+                       , MStrokeOpacity 0.4+                       , MStrokeWidth 1+                       , MFill "yellow"+                       ]+          , LineStyle [ MStroke "gray"+                      , MStrokeWidth 2+                      ]+          ]  -axis4 :: VegaLite+axis1, axis1c, axis2, axis2c, axis3, axis3c, axis4, axis4c,+  axis5, axis5c, axis6, axis6c, axis7, axis7c, axis8, axis8c :: VegaLite+axis1 = axisBase simpleData [] xQuant yQuant+axis1c = axisBase simpleData plotCfg xQuant yQuant+axis2 = axisBase simpleData [] catX yQuant+axis2c = axisBase simpleData plotCfg catX yQuant+axis3 = axisBase simpleData [] xDate yQuant+axis3c = axisBase simpleData plotCfg xDate yQuant axis4 =-  let enc = encoding-              . position X [ pName "x"-                           , pQuant-                           , PAxis [AxValues (Numbers [1, 25, 39, 90])]-                           ]-              . position Y [ pName "y", pQuant ]-    in-    toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ]---axis5 :: VegaLite+  let x = PAxis [AxValues (Numbers [1, 25, 39, 90])] : xQuant+  in axisBase simpleData [] x yQuant+axis4c =+  let x = PAxis [AxValues (Numbers [1, 25, 39, 90])] : xQuant+  in axisBase simpleData plotCfg x yQuant axis5 =-  let enc = encoding-              . position X [ pName "catX"-                           , pOrdinal-                           , PAxis [AxValues (Strings ["1", "25", "39", "dummy", "90"])]-                           ]-              . position Y [ pName "y", pQuant ]-    in-    toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ]---axis6 :: VegaLite+  let x = PAxis [AxValues (Strings ["1", "25", "39", "dummy", "90"])] : catX+  in axisBase simpleData [] x yQuant+axis5c =+  let x = PAxis [AxValues (Strings ["1", "25", "39", "dummy", "90"])] : catX+  in axisBase simpleData plotCfg x yQuant axis6 =-  let enc = encoding-              . position X [ pName "date"-                           , pTemporal-                           , PAxis [AxValues (DateTimes axDates)]-                           ]-              . position Y [ pName "y", pQuant ]+  let x = PAxis [AxValues (DateTimes axDates)] : xDate        axDates = [ [DTYear 2019, DTMonth Jan, DTDate 4 ]                 , [DTYear 2019, DTMonth Jan, DTDate 8 ]                 , [DTYear 2019, DTMonth Jan, DTDate 20 ]                 ]-                -  in -    toVegaLite [ temporalData [], enc [], mark Line [ MPoint (PMMarker []) ] ] --axis7 :: VegaLite-axis7 =-  let enc = encoding-              . position X [ pName "x"-                           , pQuant-                           , PAxis [AxLabelExpr "datum.value / 100"]-                           ]-              . position Y [ pName "y", pQuant ]-  in-    toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ]+  in axisBase temporalData [] x yQuant+axis6c =+  let x = PAxis [AxValues (DateTimes axDates)] : xDate +      axDates = [ [DTYear 2019, DTMonth Jan, DTDate 4 ]+                , [DTYear 2019, DTMonth Jan, DTDate 8 ]+                , [DTYear 2019, DTMonth Jan, DTDate 20 ]+                ] -axis8 :: VegaLite+  in axisBase temporalData plotCfg x yQuant+axis7 =+  let x = PAxis [AxLabelExpr "datum.value / 100"] : xQuant+  in axisBase simpleData [] x yQuant+axis7c =+  let x = PAxis [AxLabelExpr "datum.value / 100"] : xQuant+  in axisBase simpleData plotCfg x yQuant axis8 =-  let enc = encoding-              . position X [ pName "catX"-                           , pOrdinal-                           , PAxis [AxLabelExpr "'number' + datum.label"]-                           ]-              . position Y [ pName "y", pQuant ]-  in-    toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ]+  let x = PAxis [AxLabelExpr "'number' + datum.label"] : catX+  in axisBase simpleData [] x yQuant+axis8c =+  let x = PAxis [AxLabelExpr "'number' + datum.label"] : catX+  in axisBase simpleData plotCfg x yQuant   overlap :: OverlapStrategy -> VegaLite@@ -228,9 +241,87 @@             . position X [PName "x", PmType Quantitative]             . position Y [PName "y", PmType Quantitative] -  in toVegaLite [ prop, simpleData [], enc []+  in toVegaLite [ prop, simpleData, enc []                 , mark Line [MPoint (PMMarker [])] ]  responsiveWidth, responsiveHeight :: VegaLite responsiveWidth = responsive widthOfContainer responsiveHeight = responsive heightOfContainer+++carData :: Data+carData = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []+++carEnc :: [AxisProperty] -> [AxisProperty] -> PropertySpec+carEnc xOpts yOpts =+  let toAxis n l o = position n ([ PName l, PmType Quantitative ]+                                 ++ if null o+                                    then []+                                    else [PAxis o])++  in encoding+     . toAxis X "Horsepower" xOpts+     . toAxis Y "Miles_per_Gallon" yOpts+     . color [ MName "Origin", MmType Nominal, MLegend [] ]+     $ []++axisStyleEmpty :: VegaLite+axisStyleEmpty =+  let cfg = configure+            . configuration (AxisNamedStyles [])++  in toVegaLite [ cfg []+                , carData+                , carEnc [] []+                , mark Point []+                ]++axisStyleEmptyX :: VegaLite+axisStyleEmptyX =+  let cfg = configure+            . configuration (AxisNamedStyles [("x-style", [])])++  in toVegaLite [ cfg []+                , carData+                , carEnc [AxStyle ["x-style"]] []+                , mark Point []+                ]+++axisStyleX :: VegaLite+axisStyleX =+  let cfg = configure+            . configuration (AxisNamedStyles [("x-style", [ AxDomainColor "orange"+                                                          , AxGridColor "lightgreen"+                                                          , AxLabelExpr xexpr ])])++      xexpr = "if (datum.value <= 100, 'low:' + datum.label, 'high:' + datum.label)"++  in toVegaLite [ cfg []+                , carData+                , carEnc [AxStyle ["x-style"]] []+                , mark Point []+                ]+++axisStyleXY :: VegaLite+axisStyleXY =+  let cfg = configure+            . configuration (AxisNamedStyles [ ("x-style", [ AxDomainColor "orange"+                                                           , AxGridColor "lightgreen"+                                                           , AxLabelExpr xexpr ])+                                             , ("y-style", [ AxDomain False+                                                           , AxGrid False+                                                           , AxLabels False+                                                           , AxTicks False+                                                           , AxNoTitle ])+                                             ])++      xexpr = "if (datum.value <= 100, 'low:' + datum.label, 'high:' + datum.label)"++  in toVegaLite [ cfg []+                , carData+                , carEnc [AxStyle ["x-style"]] [AxStyle ["y-style"]]+                , mark Point []+                ]
tests/CompositeTests.hs view
@@ -19,11 +19,19 @@ testSpecs = [ ("boxplot1", boxplot1)             , ("boxplot2", boxplot2)             , ("boxplot3", boxplot3)+            , ("boxplotnobox", boxplotNoBox)+            , ("boxplotnooutliers", boxplotNoOutliers)+            , ("boxplotnomedian", boxplotNoMedian)+            , ("boxplotnorule", boxplotNoRule)+            , ("boxplotnoticks", boxplotNoTicks)             , ("errorband1", errorband1)+            , ("errorband1no", errorband1No)             , ("errorband2", errorband2)+            , ("errorband2no", errorband2No)             , ("errorbar1", errorbar1)             , ("errorbar2", errorbar2)             , ("errorbar3", errorbar3)+            , ("errorbar3no", errorbar3No)             , ("errorbar4", errorbar4)             , ("errorbar5", errorbar5)             , ("errorbar6", errorbar6)@@ -40,54 +48,61 @@ pQuant = PmType Quantitative  -bPlot :: MarkErrorExtent -> VegaLite-bPlot ext =-    let-        pop =-            dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []+bPlot :: MarkErrorExtent -> [MarkProperty] -> [MarkProperty] -> VegaLite+bPlot ext mops def =+  let pop = dataFromUrl "https://vega.github.io/vega-lite/data/population.json" [] -        enc =-            encoding-                . position X [ PName "age", PmType Ordinal ]-                . position Y [ PName "people", PmType Quantitative, PAxis [ AxTitle "Population" ] ]-    in-    toVegaLite [ pop, mark Boxplot [ MExtent ext ], enc [] ]+      enc = encoding+            . position X [ PName "age", PmType Ordinal ]+            . position Y [ PName "people", PmType Quantitative, PAxis [ AxTitle "Population" ] ] +      -- special case the empty list so as not to change the boxplot1/2/3 output+      -- (created before this capability was added).+      --+      v = [ pop, mark Boxplot (MExtent ext : mops), enc [] ]+      vs = case def of+             [] -> v+             _ -> configure (configuration (BoxplotStyle def) []) : v++    in toVegaLite vs+ boxplot1 :: VegaLite-boxplot1 = bPlot ExRange+boxplot1 = bPlot ExRange [] []  boxplot2 :: VegaLite-boxplot2 = bPlot (IqrScale 2)+boxplot2 = bPlot (IqrScale 2) [] []  boxplot3 :: VegaLite boxplot3 =-    let-        pop =-            dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []+    let mopts = [ MBox [ MColor "firebrick" ]+                , MOutliers [ MColor "black", MStrokeWidth 0.3, MSize 10 ]+                , MMedian [ MSize 18, MFill "black", MStrokeWidth 0 ]+                , MRule [ MStrokeWidth 0.4 ]+                , MTicks [ MSize 8 ]+                ] -        enc =-            encoding-                . position X [ PName "age", PmType Ordinal ]-                . position Y [ PName "people", PmType Quantitative, PAxis [ AxTitle "Population" ] ]-    in-    toVegaLite-        [ pop-        , mark Boxplot-            [ MExtent (IqrScale 0.5)-            , MBox [ MColor "firebrick" ]-            , MOutliers [ MColor "black", MStrokeWidth 0.3, MSize 10 ]-            , MMedian [ MSize 18, MFill "black", MStrokeWidth 0 ]-            , MRule [ MStrokeWidth 0.4 ]-            , MTicks [ MSize 8 ]-            ]-        , enc []-        ]+    in bPlot (IqrScale 0.5) mopts [] +-- Could combine into one plot, but useful to see the individual elements turned off+--+-- We need to set the default values to turn on ticks (since they are off by+-- default).+-- +defConfig :: [MarkProperty]+defConfig = [ MTicks [] ]++boxplotNoBox, boxplotNoOutliers, boxplotNoMedian, boxplotNoRule, boxplotNoTicks :: VegaLite+boxplotNoBox = bPlot (IqrScale 0.5) [ MNoBox ] defConfig+boxplotNoOutliers = bPlot (IqrScale 0.5) [ MNoOutliers ] defConfig+boxplotNoMedian = bPlot (IqrScale 0.5) [ MNoMedian ] defConfig+boxplotNoRule = bPlot (IqrScale 0.5) [ MNoRule ] defConfig+boxplotNoTicks = bPlot (IqrScale 0.5) [ MNoTicks ] defConfig+ -- Note: at present only called with ci or stdev arguments -eBand :: T.Text -> VegaLite-eBand ext =+eBand :: T.Text -> Bool -> VegaLite+eBand ext hasBorders =     let         cars =             dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []@@ -138,21 +153,25 @@                     , PTitle ("Miles per Gallon " <> label)                     ] -        mopts = [ MExtent summary, MInterpolate Monotone, MBorders [] ]+        mopts = [ MExtent summary+                , MInterpolate Monotone+                , if hasBorders then MBorders [] else MNoBorders+                ]+     in     toVegaLite [ cars                , mark ErrorBand mopts                , enc [] ]  -errorband1 :: VegaLite-errorband1 =-    eBand "ci"+errorband1, errorband1No :: VegaLite+errorband1 = eBand "ci" True+errorband1No = eBand "ci" False  -errorband2 :: VegaLite-errorband2 =-    eBand "stdev"+errorband2, errorband2No :: VegaLite+errorband2 = eBand "stdev" True+errorband2No = eBand "stdev" False   eBar :: MarkErrorExtent -> VegaLite@@ -188,14 +207,15 @@     eBar StdDev  -errorbar3 :: VegaLite-errorbar3 =+ebarsColor :: Bool -> VegaLite+ebarsColor hasTicks =     let         des =             description "Error bars with color encoding"          specErrorBars =-            asSpec [ mark ErrorBar [ MTicks [] ], encErrorBars [] ]+            asSpec [ mark ErrorBar [ if hasTicks then MTicks [] else MNoTicks ]+                   , encErrorBars [] ]          encErrorBars =             encoding@@ -218,6 +238,11 @@         , dataFromUrl "https://vega.github.io/vega-lite/data/barley.json" []         , layer [ specErrorBars, specPoints ]         ]+++errorbar3, errorbar3No :: VegaLite+errorbar3 = ebarsColor True+errorbar3No = ebarsColor False   yieldData :: [DataColumn] -> Data
tests/ConditionalTests.hs view
@@ -16,6 +16,7 @@             , ("axisCondition1", axisCondition1)             , ("axisCondition2", axisCondition2)             , ("axisCondition3", axisCondition3)+            , ("axisconditionlabeloffset", axisConditionLabelOffset)             , ("axisDateCondition1", axisDateCondition1)             , ("selectionCondition1", selectionCondition1)             , ("selectionCondition2", selectionCondition2)@@ -25,13 +26,29 @@             , ("bindScales1", bindScales1)             , ("bindScales2", bindScales2)             ]-            +++movieData, carData :: Data+movieData = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []+carData = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []++rtRating :: BuildEncodingSpecs+rtRating = position Y [ PName "Rotten_Tomatoes_Rating", PmType Quantitative ]++encCars :: [EncodingSpec] -> PropertySpec+encCars = encoding+          . position Y [ PName "Origin", PmType Ordinal ]+          . position X [ PName "Cylinders", PmType Ordinal ]++encHorses :: [EncodingSpec] -> PropertySpec+encHorses = encoding+            . position X [ PName "Horsepower", PmType Quantitative ]+            . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]++ markCondition1 :: VegaLite markCondition1 =     let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []-         config =             configure                 . configuration (MarkStyle [ MRemoveInvalid False ])@@ -39,7 +56,7 @@         enc =             encoding                 . position X [ PName "IMDB_Rating", PmType Quantitative ]-                . position Y [ PName "Rotten_Tomatoes_Rating", PmType Quantitative ]+                . rtRating                 . color                     [ MDataCondition                         [ ( Or (Expr "datum.IMDB_Rating === null")@@ -51,7 +68,7 @@                     ]     in     toVegaLite [ config []-               , dataVals+               , movieData                -- Vega-Lite 4 turned off tooltips by default, so                -- enable them here                , mark Point [ MTooltip TTEncoding ]@@ -82,17 +99,15 @@  axisTest :: [AxisProperty] -> VegaLite axisTest axConds =-  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []--      enc = encoding+  let enc = encoding                 . position X                     [ PName "IMDB_Rating"                     , PmType Quantitative                     , PAxis (AxTickCount 20 : axConds)                     ]-                . position Y [ PName "Rotten_Tomatoes_Rating", PmType Quantitative ]+                . rtRating -  in toVegaLite [ width 600, height 600, dvals, mark Point [ MOpacity 0.1 ], enc [] ]+  in toVegaLite [ width 600, height 600, movieData, mark Point [ MOpacity 0.1 ], enc [] ]   axisCondition1 :: VegaLite@@ -113,6 +128,10 @@            , AxDataCondition (Expr "(datum.value >= 3) && (datum.value <= 7)")                               (CAxTickDashOffset 4 0)            -}+           , AxDataCondition (Expr "(datum.value > 0) && (datum.value < 3)")+                              (CAxTickSize 20 5)+           , AxDataCondition (Expr "(datum.value >= 1) && (datum.value <= 4)")+                              (CAxLabelPadding 20 5)            ]  @@ -128,16 +147,19 @@            , AxDataCondition (Expr "datum.value >=9") (CAxLabelOpacity 0.3 0.8)            ] +-- Vega Lite 4.5.0 or later+axisConditionLabelOffset :: VegaLite+axisConditionLabelOffset =+  axisTest [ AxDataCondition (Expr "datum.value <= 5") (CAxLabelOffset 10 5) ] + -- add a basic test of date handling (so that I can check the example given in the -- documentation, or at least one similar to it, even if in this case it affects -- all grid lines). -- axisDateCondition1 :: VegaLite axisDateCondition1 =-  let dataVals = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--      enc =+  let enc =         encoding           . position X [ PName "Year"                        , PmType Temporal@@ -155,15 +177,12 @@        mopts = [ MExtent Iqr, MInterpolate Monotone, MBorders [] ] -  in toVegaLite [ width 600, dataVals, enc [], mark ErrorBand mopts ]+  in toVegaLite [ width 600, carData, enc [], mark ErrorBand mopts ]   selectionCondition1 :: VegaLite selectionCondition1 =-    let dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--        sel =+    let sel =             selection                 . select "alex"                     Interval@@ -177,23 +196,16 @@                     , SelectionMark [ SMFill "#fdbb84", SMFillOpacity 0.5, SMStroke "#e34a33" ]                     ] -        enc =-            encoding-                . position Y [ PName "Origin", PmType Ordinal ]-                . position X [ PName "Cylinders", PmType Ordinal ]+        enc = encCars                 . color [ MAggregate Count, MName "*", MmType Quantitative ]     in     toVegaLite-        [ dataVals, sel [], mark Rect [ MCursor CGrab ], enc [] ]+        [ carData, sel [], mark Rect [ MCursor CGrab ], enc [] ]   selectionCondition2 :: VegaLite selectionCondition2 =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--        sel =+    let sel =             selection                 . select "alex"                     Interval@@ -207,10 +219,7 @@                     , SelectionMark [ SMFill "#fdbb84", SMFillOpacity 0.5, SMStroke "#e34a33" ]                     ] -        enc =-            encoding-                . position Y [ PName "Origin", PmType Ordinal ]-                . position X [ PName "Cylinders", PmType Ordinal ]+        enc = encCars                 . color                     [ MSelectionCondition                         (And (SelectionName "alex") (SelectionName "morgan"))@@ -219,16 +228,12 @@                     ]     in     toVegaLite-        [ dataVals, sel [], mark Rect [ MCursor CGrab ], enc [] ]+        [ carData, sel [], mark Rect [ MCursor CGrab ], enc [] ]   selectionCondition3 :: VegaLite selectionCondition3 =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--        trans =+    let trans =             transform                 . filter (FCompose (And (Selection "brush") (Expr "datum.Weight_in_lbs > 3000"))) @@ -236,13 +241,8 @@             selection                 . select "brush" Interval [] -        enc1 =-            encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]-         spec1 =-            asSpec [ sel [], mark Point [], enc1 [] ]+            asSpec [ sel [], mark Point [], encHorses [] ]          enc2 =             encoding@@ -253,16 +253,12 @@             asSpec [ trans [], mark Point [], enc2 [] ]     in     toVegaLite-        [ dataVals, vConcat [ spec1, spec2 ] ]+        [ carData, vConcat [ spec1, spec2 ] ]   selectionCondition4 :: VegaLite selectionCondition4 =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--        sel =+    let sel =             selection                 . select "mySelection"                     Interval@@ -271,10 +267,7 @@                     , Translate "[mousedown[!event.shiftKey], mouseup] > mousemove"                     ] -        enc =-            encoding-                . position Y [ PName "Origin", PmType Ordinal ]-                . position X [ PName "Cylinders", PmType Ordinal ]+        enc = encCars                 . color                     [ MSelectionCondition                         (SelectionName "mySelection")@@ -283,16 +276,12 @@                     ]     in     toVegaLite-        [ dataVals, sel [], mark Rect [ MCursor CGrab ], enc [] ]+        [ carData, sel [], mark Rect [ MCursor CGrab ], enc [] ]   selectionCondition5 :: VegaLite selectionCondition5 =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--        sel =+    let sel =             selection                 . select "mySelection"                     Interval@@ -302,10 +291,7 @@                     , Translate "[mousedown[!event.shiftKey], mouseup] > mousemove"                     ] -        enc =-            encoding-                . position Y [ PName "Origin", PmType Ordinal ]-                . position X [ PName "Cylinders", PmType Ordinal ]+        enc = encCars                 . color                     [ MSelectionCondition                         (SelectionName "mySelection")@@ -314,44 +300,28 @@                     ]     in     toVegaLite-        [ dataVals, sel [], mark Rect [ MCursor CGrab ], enc [] ]+        [ carData, sel [], mark Rect [ MCursor CGrab ], enc [] ]   bindScales1 :: VegaLite bindScales1 =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"--        sel =+    let sel =             selection                 . select "myZoomPan" Interval [ BindScales ] -        enc =-            encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]     in     toVegaLite-        [ width 300, height 300, dataVals [], sel [], mark Circle [], enc [] ]+        [ width 300, height 300, carData, sel [], mark Circle [], encHorses [] ]   bindScales2 :: VegaLite bindScales2 =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"--        sel =+    let sel =             selection                 . select "myZoomPan"                     Interval                     [ BindScales, Clear "click[event.shiftKey]" ] -        enc =-            encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]     in     toVegaLite-        [ width 300, height 300, dataVals [], sel [], mark Circle [], enc [] ]+        [ width 300, height 300, carData, sel [], mark Circle [], encHorses [] ]
tests/ConfigTests.hs view
@@ -34,40 +34,51 @@             , ("paddingResize", paddingResizeCfg)             , ("vbTest", vbTest)             , ("axisCfg1", axisCfg1)+            , ("fontCfg", fontCfg)             , ("titleCfg1", titleCfg1)             , ("titleCfg2", titleCfg2)             , ("titleCfg3", titleCfg3)             ] ++carData :: Data+carData = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []+++xHorse, yMPG :: BuildEncodingSpecs+xHorse = position X [ PName "Horsepower", PmType Quantitative ]+yMPG = position Y [ PName "Miles_per_Gallon", PmType Quantitative ]++yCount :: [PositionChannel] -> BuildEncodingSpecs+yCount opts = position Y ([ PAggregate Count, PmType Quantitative ] ++ opts)+++mCylinders, mOrigin :: [MarkChannel]+mCylinders = [ MName "Cylinders", MmType Ordinal ]+mOrigin = [ MName "Origin", MmType Nominal ]++ singleVis :: ([a] -> (VLProperty, VLSpec)) -> VegaLite singleVis config =-    let-        cars =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []+  let scatterEnc =+        encoding+        . xHorse+        . yMPG+        . color mCylinders+        . shape mOrigin -        scatterEnc =-            encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]-                . color [ MName "Cylinders", MmType Ordinal ]-                . shape [ MName "Origin", MmType Nominal ]-    in-    toVegaLite [ title "Car Scatter" [], config [], cars, width 200, height 200, mark Point [ MSize 100 ], scatterEnc [] ]+  in toVegaLite [ title "Car Scatter" [], config [], carData, width 200, height 200, mark Point [ MSize 100 ], scatterEnc [] ]   {- TODO: padding causes spec to be invalid -} compositeVis :: ([a] -> (VLProperty, VLSpec)) -> VegaLite compositeVis config =-    let-        cars =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--        scatterEnc =+    let scatterEnc =             encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]-                . color [ MName "Cylinders", MmType Ordinal ]-                . shape [ MName "Origin", MmType Nominal ]+                . xHorse+                . yMPG+                . color mCylinders+                . shape mOrigin          scatterSpec =             asSpec [ title "Car Scatter" [], width 200, height 200@@ -76,15 +87,15 @@          barEnc =             encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PAggregate Count, PmType Quantitative ]-                . color [ MName "Origin", MmType Nominal ]+                . xHorse+                . yCount []+                . color mOrigin          streamEnc =             encoding                 . position X [ PName "Year", PmType Temporal, PTimeUnit Year ]-                . position Y [ PAggregate Count, PmType Quantitative, PStack StCenter, PAxis [] ]-                . color [ MName "Origin", MmType Nominal ]+                . yCount [ PStack StCenter, PAxis [] ]+                . color mOrigin          barSpec =             asSpec [ title "Car Histogram" [], width 200, height 200@@ -100,33 +111,29 @@             resolve                 . resolution (RScale [ ( ChColor, Independent ), ( ChShape, Independent ) ])     in-    toVegaLite [ config [], cars, hConcat [ scatterSpec, barSpec, streamSpec ], res [] ]+    toVegaLite [ config [], carData, hConcat [ scatterSpec, barSpec, streamSpec ], res [] ]   vbTest :: VegaLite vbTest =-    let-        cars =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []--        scatterEnc =+    let scatterEnc =             encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]-                . color [ MName "Cylinders", MmType Ordinal ]-                . shape [ MName "Origin", MmType Nominal ]+                . xHorse+                . yMPG+                . color mCylinders+                . shape mOrigin          barEnc =             encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PAggregate Count, PmType Quantitative ]-                . color [ MName "Origin", MmType Nominal ]+                . xHorse+                . yCount []+                . color mOrigin          streamEnc =             encoding                 . position X [ PName "Year", PmType Temporal, PTimeUnit Year ]-                . position Y [ PAggregate Count, PmType Quantitative, PStack StCenter, PAxis [] ]-                . color [ MName "Origin", MmType Nominal ]+                . yCount [ PStack StCenter, PAxis [] ]+                . color mOrigin          scatterSpec =             asSpec@@ -143,9 +150,9 @@                 , width 200                 , height 200                 , viewBackground-                    [ VBFill (Just "white")+                    [ VBFill "white"                     , VBCornerRadius 18-                    , VBStroke (Just "red")+                    , VBStroke "red"                     , VBStrokeWidth 4                     , VBStrokeCap CRound                     , VBStrokeDash [ 10, 10 ]@@ -158,12 +165,12 @@         cfg =             configure                 . configuration-                    (NamedStyles+                    (MarkNamedStyles                         [ ( "myStyle", [ MFill "red", MFillOpacity 0.1, MStrokeOpacity 1 ] )                         , ( "mySecondStyle", [ MFill "black", MStroke "blue" ] )                         ]                     )-                . configuration (View [ ViewBackgroundStyle [ VBFill (Just "#feb") ] ])+                . configuration (ViewStyle [ ViewBackgroundStyle [ VBFill "#feb" ] ])          streamSpec =             asSpec@@ -182,7 +189,7 @@     toVegaLite         [ cfg []         , background "yellow"-        , cars+        , carData         , hConcat [ scatterSpec, barSpec, streamSpec ]         , res []         ]@@ -196,10 +203,10 @@ darkCfg :: VegaLite darkCfg =     configure-        . configuration (Background "black")+        . configuration (BackgroundStyle "black")         . configuration (TitleStyle [ TFont "Roboto", TColor "#fff" ])         . configuration (Axis [ DomainColor "yellow", GridColor "rgb(255,255,200)", GridOpacity 0.2, LabelColor "#fcf", TickColor "white", TitleColor "rgb(200,255,200)", LabelFont "Roboto", TitleFont "Roboto" ])-        . configuration (Legend [ LeFillColor "#333", LeStrokeColor "#444", LeTitleColor "rgb(200,200,200)", LeLabelColor "white", LeSymbolFillColor "red", LeGradientStrokeColor "yellow", LeLabelFont "Roboto", LeTitleFont "Roboto" ])+        . configuration (LegendStyle [ LeFillColor "#333", LeStrokeColor "#444", LeTitleColor "rgb(200,200,200)", LeLabelColor "white", LeSymbolFillColor "red", LeGradientStrokeColor "yellow", LeLabelFont "Roboto", LeTitleFont "Roboto" ])         & compositeVis  @@ -223,8 +230,8 @@ paddingTest :: Autosize -> VegaLite paddingTest a =   configure-  . configuration (Autosize [ a ])-  . configuration (Padding (PEdges 90 60 30 0))+  . configuration (AutosizeStyle [ a ])+  . configuration (PaddingStyle (PEdges 90 60 30 0))   & singleVis  @@ -252,25 +259,27 @@        & singleVis  +fontCfg :: VegaLite+fontCfg =+    configure+       . configuration (FontStyle "Comic Sans MS")+       & singleVis++ titleOpts :: [PropertySpec] titleOpts =-  [ dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" [],-    width 200+  [ carData+  , width 200   , height 200   , mark Circle []-  , encoding-      . position X [ PName "Horsepower"-                   , PmType Quantitative ]-      . position Y [ PName "Miles_per_Gallon"-                   , PmType Quantitative ]-      $ []+  , encoding . xHorse . yMPG $ []   ]   titleCfg1 :: VegaLite titleCfg1 =   toVegaLite-    ((title "Car\nScatter" [ TSubtitle "A subtitle\nalso over two lines" ])+    (title "Car\nScatter" [ TSubtitle "A subtitle\nalso over two lines" ]      : titleOpts)  @@ -286,7 +295,7 @@   , TSubtitlePadding 60   , TLineHeight 20   , TdX (-30)-  , TdY (10)+  , TdY 10   ]  subtitle :: TitleConfig@@ -295,8 +304,7 @@ titleCfg2 :: VegaLite titleCfg2 =   toVegaLite-    ((title "Car\nScatter"-      (subtitle : cfgOpts))+    (title "Car\nScatter" (subtitle : cfgOpts)       : titleOpts)  
tests/DataTests.hs view
@@ -53,6 +53,9 @@             , ("filter2", filter2)             , ("annotate1", annotate1)             , ("null1", null1)+            , ("domain1", domain1)+            , ("domain2", domain2)+            , ("domain3", domain3)             -- , ("key1", key1)             ] @@ -241,7 +244,7 @@     toVegaLite         [ width 700         , height 500-        , configure $ configuration (View [ ViewStroke Nothing ]) []+        , configure $ configuration (ViewStyle [ ViewNoStroke ]) []         , dataFromUrl "https://vega.github.io/vega-lite/data/londonBoroughs.json" [ TopojsonFeature "boroughs" ]         , mark Geoshape []         , encoding $ color [ MName "id", MmType Nominal ] []@@ -259,7 +262,7 @@     toVegaLite         [ width 300         , height 400-        , configure $ configuration (View [ ViewStroke Nothing ]) []+        , configure $ configuration (ViewStyle [ ViewNoStroke ]) []         , dataFromJson geojson [ JSON "features" ]         , projection [ PrType Orthographic ]         , encoding (color [ MName "properties.Region", MmType Nominal, MLegend [ LNoTitle ] ] [])@@ -666,6 +669,31 @@                  . dataRow [("x", Number 7), ("y", Number 20)]                  $ []              ]+++domainData :: Data+domainData = dataFromColumns []+             . dataColumn "x" (Numbers [ 1, 2, 3, 4 ])+             . dataColumn "y" (Numbers [ 95, 97, 100, 105 ])+             $ []+++domain :: [ScaleProperty] -> VegaLite+domain yExtra =+  let enc = encoding+            . position X [PName "x", PmType Quantitative]+            . position Y [PName "y", PmType Quantitative, PScale (SZero False : yExtra)]+            $ []++      mopts = [MPoint (PMMarker [])]++  in toVegaLite [domainData, enc, mark Line mopts]+++domain1, domain2, domain3 :: VegaLite+domain1 = domain []+domain2 = domain [SDomain (DNumbers [90, 100])]+domain3 = domain [SDomain (DUnionWith (DNumbers [90, 100]))]   {-
+ tests/EncodingTests.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}++{-++Limited set of encoding-related tests, as it is used in every test.++-}++module EncodingTests (testSpecs) where++import Graphics.Vega.VegaLite++testSpecs :: [(String, VegaLite)]+testSpecs = [ ("strokedashgroup", strokeDashGroup)+            , ("strokedashline", strokeDashLine)+            ]+            ++strokeDashGroup :: VegaLite+strokeDashGroup =+  toVegaLite [ dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []+             , mark Line []+             , encoding+               . position X [ PName "date", PmType Temporal ]+               . position Y [ PName "price", PmType Quantitative ]+               . strokeDash [ MName "symbol", MmType Nominal ]+               $ []+             ]++strokeDashLine :: VegaLite+strokeDashLine =+  toVegaLite [ dataFromColumns []+               . dataColumn "a" (Strings [ "A", "B", "D", "E", "E", "G", "H"])+               . dataColumn "b" (Numbers [ 28, 55, 91, 81, 81, 19, 87 ])+               . dataColumn "predicted" (Booleans [False, False, False, False, True, True, True])+               $ []+             , mark Line []+             , encoding+               . position X [ PName "a", PmType Ordinal ]+               . position Y [ PName "b", PmType Quantitative ]+               . strokeDash [ MName "predicted", MmType Nominal ]+               $ []+             ]
tests/FillStrokeTests.hs view
@@ -1,4 +1,6 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}  -- -- Based on the Elm VegaLite FillStrokeTests.elm as of version 1.12.0@@ -9,8 +11,15 @@ -- module FillStrokeTests (testSpecs) where --- import qualified Data.Text as T+import qualified Data.Text as T +import Data.Aeson (Value)+import Data.Aeson.QQ.Simple (aesonQQ)++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif+ import Graphics.Vega.VegaLite hiding (filter, repeat)  testSpecs :: [(String, VegaLite)]@@ -32,6 +41,17 @@             , ("gradientr1", gradientr1)             , ("gradientr2", gradientr2)             , ("gradientr3", gradientr3)+            , ("vrounded", vrounded)+            , ("hrounded", hrounded)+            , ("strokedash1", strokeDash1)+            , ("strokedash2", strokeDash2)+            , ("strokedash3", strokeDash3)+            , ("strokedash4", strokeDash4)+            , ("strokedash5", strokeDash5)+            , ("strokedash6", strokeDash6)+            , ("strokedash7", strokeDash7)+            , ("strokedash8", strokeDash8)+            , ("strokedash9", strokeDash9)             ]  encChart :: ([a] -> [EncodingSpec]) -> VegaLite@@ -207,3 +227,188 @@              ]    in gradientTest markType+++{-+From https://vega.github.io/vega-lite/docs/bar.html#bar-chart-with-rounded-corners++{+  "data": {+    "values": [+      {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},+      {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},+      {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}+    ]+  },+  "mark": {"type": "bar", "cornerRadiusEnd": 4},+  "encoding": {+    "x": {"field": "a", "type": "ordinal"},+    "y": {"field": "b", "type": "quantitative"}+  }+}++-}++barData :: Value+barData = [aesonQQ|+[+  {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},+  {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},+  {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}+]+|]++rounded :: Position -> Position -> VegaLite+rounded h v =+  toVegaLite [ dataFromJson barData []+             , mark Bar [ MCornerRadiusEnd 4 ]+             , encoding+               . position h [ PName "a", PmType Ordinal ]+               . position v [ PName "b", PmType Quantitative ]+               $ []+             ]++vrounded :: VegaLite+vrounded = rounded X Y++hrounded :: VegaLite+hrounded = rounded Y X+++stockData :: Data+stockData = dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []++xDate, yPrice :: BuildEncodingSpecs+xDate = position X [ PName "date", PmType Temporal ]+yPrice = position Y [ PName "price", PmType Quantitative ]++strokeDashTest :: [MarkChannel] -> VegaLite+strokeDashTest sOpts =+  let enc = encoding+            . xDate+            . yPrice+            . strokeDash ([ MName "symbol", MmType Nominal ] ++ sOpts)++      lineOpts = [MStrokeWidth 1, MOpacity 0.6]++  in toVegaLite [ width 350, stockData, enc [], mark Line lineOpts ]+++strokeDash1 :: VegaLite+strokeDash1 = strokeDashTest []++strokeDash2 :: VegaLite+strokeDash2 = strokeDashTest [ MScale+                           [ SDomain (DStrings [ "AAPL", "AMZN", "GOOG", "IBM", "MSFT" ])+                           , SRange (RNumberLists [ [ 1, 0 ], [ 3, 1 ], [ 2, 3 ], [ 4, 4 ], [ 5, 6 ] ])+                           ]+                         ]++pName :: T.Text -> PositionChannel+pName = PName++mName :: T.Text -> MarkChannel+mName = MName++pQuant :: PositionChannel+pQuant = PmType Quantitative++mNominal, mOrdinal :: MarkChannel+mNominal = MmType Nominal+mOrdinal = MmType Ordinal+++sDash :: [MarkChannel] -> VegaLite+sDash sdOpts =+  let dvals = dataFromColumns []+              . toCol "x" [ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 ]+              . toCol "y" [ 100, 100, 90, 90, 80, 80, 70, 70, 60, 60, 50, 50, 40, 40, 30, 30, 20, 20, 10, 10 ]+              . toCol "cat" [ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10 ]++      toCol l = dataColumn l . Numbers++      encBase = encoding+                . position X [ pName "x", pQuant ]+                . position Y [ pName "y", pQuant ]++      enc1 = encBase+             . strokeDash ([ mName "cat", mNominal ] ++ sdOpts)++      spec1 = asSpec [ title "Nominal" [], width 200, enc1 [], mark Line [] ]++      enc2 = encBase+             . strokeDash ([ mName "cat", mOrdinal ] ++ sdOpts)++      spec2 = asSpec [ title "Ordinal" [], width 200, enc2 [], mark Line [] ]++      res = resolve+            . resolution (RScale [ ( ChStrokeDash, Independent ) ])++      cfg = configure+            . configuration (Axis [NoTitle, Grid False])+            . configuration (LineStyle [MStrokeWidth 1, MColor "orange", MOpacity 0.6])++  in toVegaLite [ dvals [], cfg [], res [], vlConcat [ spec1, spec2 ] ]+++d0, d1, d2, d3, d4, d5, d6, d7, d8, d9 :: [Double]+d0 = [ 1, 0 ]+d1 = [ 16, 4 ]+d2 = [ 10, 4 ]+d3 = [ 8, 4 ]+d4 = [ 8, 4, 4, 4 ]+d5 = [ 6, 4 ]+d6 = [ 5, 4 ]+d7 = [ 4, 6 ]+d8 = [ 2, 4 ]+d9 = [ 1, 3 ]++strokeDash3, strokeDash4 :: VegaLite+strokeDash3 = sDash []+strokeDash4 = sDash [ MScale+                      [ SDomain (DNumbers [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])+                      , SRange (RNumberLists [d0, d6, d8, d4, d9, d1, d5, d3, d7, d2])+                      ]+                    ]+++scaledStrokeDash :: Double -> VegaLite+scaledStrokeDash dashScale =+  let scaleDash = map (map (dashScale *))++      dvals = dataSequenceAs 0 100 0.1 "x0"++      trans = transform+              . calculateAs "abs(sin(datum.x0+random()))" "y0"+              . calculateAs "datum.x0 %10" "x"+              . calculateAs "floor(datum.x0 / 10)" "cat"+              . calculateAs "datum.y0 + datum.cat" "y"++      enc = encoding+            . position X [ pName "x", pQuant, PAxis [ AxGrid False ] ]+            . position Y [ pName "y", pQuant, PAxis [ AxGrid False ] ]+            . strokeDash+                    [ mName "cat"+                    , mOrdinal+                    , MScale+                        [ SDomain (DNumbers [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ])+                        , SRange (RNumberLists (scaleDash [ d0, d1, d2, d3, d4, d5, d6, d7, d8, d9 ]))+                        ]+                    ]++  in toVegaLite [ title ("Dash scale " <> T.pack (show dashScale)) []+                , width 300+                , height 300+                , dvals+                , trans []+                , enc []+                , mark Line []+                ]+++strokeDash5, strokeDash6, strokeDash7, strokeDash8, strokeDash9 :: VegaLite+strokeDash5 = scaledStrokeDash 0.2+strokeDash6 = scaledStrokeDash 0.5+strokeDash7 = scaledStrokeDash 1+strokeDash8 = scaledStrokeDash 2+strokeDash9 = scaledStrokeDash 4
tests/Gallery/Advanced.hs view
@@ -369,10 +369,10 @@          cfg =             configure-                . configuration (View [ ViewStroke Nothing ])+                . configuration (ViewStyle [ ViewNoStroke ])                 . configuration (AxisX [ Domain False, LabelAngle 0, TickColor "#ccc" ])                 . configuration-                    (NamedStyles+                    (MarkNamedStyles                         [ ( "label", [ MBaseline AlignMiddle, MAlign AlignRight, MdX (-5), MTooltip TTNone ] )                         , ( "tick", [ MOrient Horizontal, MTooltip TTNone ] )                         ]
tests/Gallery/Area.hs view
@@ -246,9 +246,9 @@          cfg =             configure-                . configuration (View [ ViewStroke Nothing ])+                . configuration (ViewStyle [ ViewNoStroke ])                 . configuration (Axis [ Domain False, Ticks False, Labels False, Grid False ])-                . configuration (ConcatStyle [ ConcatSpacing 10 ])+                . configuration (ConcatStyle [ CompSpacing 10 ])          res =             resolve
tests/Gallery/Bar.hs view
@@ -50,6 +50,11 @@ pQuant = PmType Quantitative  +noStroke :: [ConfigureSpec] -> PropertySpec+noStroke = configure+           . configuration (ViewStyle [ ViewNoStroke ])++ -- bar1 in GalleryBar.elm bar1 :: VegaLite bar1 =@@ -138,10 +143,8 @@                 . column [ FName "age", FmType Ordinal ]                 . color [ MName "gender", MmType Nominal, MScale [ SRange (RStrings [ "#EA98D2", "#659CCA" ]) ] ] -        config =-            configure+        config = noStroke                 . configuration (Axis [ DomainWidth 1 ])-                . configuration (View [ ViewStroke Nothing ])     in     toVegaLite         [ des@@ -395,7 +398,9 @@                    ]          config =-            configure . configuration (NamedStyle "label" [ MAlign AlignLeft, MBaseline AlignMiddle, MdX 3 ])+            configure . configuration (MarkNamedStyles+                                       [( "label"+                                        , [ MAlign AlignLeft, MBaseline AlignMiddle, MdX 3 ])])     in     toVegaLite [ des, dvals [], enc [], layer [ specBar, specText ], config [] ] @@ -434,10 +439,6 @@         des =             description "Isotype bar chart inspired by this Only An Ocean Between, 1943. Population Live Stock, p.13." -        config =-            configure-                . configuration (View [ ViewStroke Nothing ])-         dvals =             dataFromRows []                 . toRows "Great Britain" [ ( "cattle", 3 ), ( "pigs", 2 ), ( "sheep", 10 ) ]@@ -477,7 +478,7 @@                 . opacity [ MNumber 1 ]                 . size [ MNumber 200 ]     in-    toVegaLite [ des, config [], width 800, height 200, dvals [], mark Point [ MFilled True ], enc [] ]+    toVegaLite [ des, noStroke [], width 800, height 200, dvals [], mark Point [ MFilled True ], enc [] ]   -- bar20 in GalleryBar.elm@@ -487,10 +488,6 @@         des =             description "Isotype bar chart using emojis for symbols" -        config =-            configure-                . configuration (View [ ViewStroke Nothing ])-         dvals =             dataFromRows []                 . toRows "Great Britain" [ ( "cattle", 3 ), ( "pigs", 2 ), ( "sheep", 10 ) ]@@ -509,7 +506,7 @@                 . text [ TName "emoji", TmType Nominal ]                 . size [ MNumber 65 ]     in-    toVegaLite [ des, config [], width 800, height 200, dvals [], trans [], mark Text [ MBaseline AlignMiddle ], enc [] ]+    toVegaLite [ des, noStroke [], width 800, height 200, dvals [], trans [], mark Text [ MBaseline AlignMiddle ], enc [] ]   -- bar3 in GalleryBar.elm, see bar3 above@@ -614,8 +611,7 @@                     , MLegend [ LOrient LOTop, LTitle "" ]                     ] -      cfg = configure-            . configuration (View [ ViewStroke Nothing ])+      cfg = noStroke             . configuration (Axis [ Grid False ])    in toVegaLite [ width 300@@ -696,9 +692,6 @@ wilkinsonDotPlot =   let desc = description "A Wilkinson dot plot" -      cfg = configure-            . configuration (View [ ViewStroke Nothing ])-       dvals = dataFromColumns []               . dataColumn "data" (Numbers [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 ]) @@ -716,7 +709,7 @@    in toVegaLite         [ desc-        , cfg []+        , noStroke []         , height 100         , dvals []         , trans []
tests/Gallery/Facet.hs view
@@ -194,11 +194,14 @@                 . row                     [ FName "symbol"                     , FmType Nominal-                    , FHeader [ HTitle "Stock price"+                    , FHeader [ HTitle "Stock\nprice"+                              , HTitleLineHeight 20                               , HLabelAngle 0                               -- I don't know why the labels only align                               -- when AlignLeft is used.                               , HLabelAlign AlignLeft+                              , HLabelExpr "'{' + datum.label + '}'"+                              , HLabelFontStyle "italic"                               ]                     ] @@ -208,6 +211,6 @@          cfg =             configure-                . configuration (View [ ViewStroke Nothing ])+                . configuration (ViewStyle [ ViewNoStroke ])     in     toVegaLite [ des, width 300, height 50, cfg [], res [], dvals [], mark Area [], enc [] ]
tests/Gallery/Geo.hs view
@@ -30,7 +30,7 @@ cfg :: [ConfigureSpec] -> PropertySpec cfg =     configure-        . configuration (View [ ViewStroke Nothing ])+        . configuration (ViewStyle [ ViewNoStroke ])   geo1 :: VegaLite
tests/Gallery/Interaction.hs view
@@ -42,7 +42,7 @@          config =             configure-                . configuration (Scale [ SCBandPaddingInner 0.2 ])+                . configuration (ScaleStyle [ SCBandPaddingInner 0.2 ])          dvals =             dataFromColumns []
tests/Gallery/Label.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}  -- -- Based on the Elm VegaLite GalleryLabel.elm (from development of version@@ -6,6 +7,9 @@ -- module Gallery.Label (testSpecs) where +import Data.Aeson (Value)+import Data.Aeson.QQ.Simple (aesonQQ)+ import Graphics.Vega.VegaLite  import Prelude hiding (filter, lookup, repeat)@@ -13,13 +17,23 @@ testSpecs :: [(String, VegaLite)] testSpecs = [ ("label1", label1)             , ("label2", label2)+            , ("label2r", label2r)             , ("label3", label3)             , ("label4", label4)             , ("label5", label5)             , ("label6", label6)             , ("label7", label7)+            , ("label8", label8)+            , ("label9", label9)+            , ("voyager", voyager)+            , ("baselines", baselines)             ] ++noStroke :: [ConfigureSpec] -> PropertySpec+noStroke = configure . configuration (ViewStyle [ViewNoStroke])++ label1 :: VegaLite label1 =     let@@ -43,18 +57,17 @@             asSpec [ mark Text [ MStyle [ "label" ] ], encoding (text [ TName "b", TmType Quantitative ] []) ]          config =-            configure . configuration (NamedStyle "label" [ MAlign AlignLeft, MBaseline AlignMiddle, MdX 3 ])+            configure . configuration (MarkNamedStyles [( "label"+                                                        , [ MAlign AlignLeft, MBaseline AlignMiddle, MdX 3 ])+                                                       ])+     in     toVegaLite [ des, dvals [], enc [], layer [ specBar, specText ], config [] ]  -label2 :: VegaLite-label2 =-    let-        des =-            description "Layering text over 'heatmap'"--        encPosition =+label2Base :: [ScaleConfig] -> VegaLite+label2Base opts =+    let encPosition =             encoding                 . position X [ PName "Cylinders", PmType Ordinal ]                 . position Y [ PName "Origin", PmType Ordinal ]@@ -74,13 +87,14 @@         specText =             asSpec [ mark Text [], encText [] ] +        scOpts = [ SCBandPaddingInner 0, SCBandPaddingOuter 0 ] ++ opts         config =             configure-                . configuration (Scale [ SCBandPaddingInner 0, SCBandPaddingOuter 0 ])+                . configuration (ScaleStyle scOpts)                 . configuration (TextStyle [ MBaseline AlignMiddle ])     in     toVegaLite-        [ des+        [ description "Layering text over 'heatmap'"         , dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []         , encPosition []         , layer [ specRect, specText ]@@ -88,6 +102,12 @@         ]  +label2, label2r :: VegaLite+label2 = label2Base [SCXReverse False]+label2r = label2Base [SCXReverse True]+++-- TODO: this has been re-worked in elm label3 :: VegaLite label3 =     let@@ -115,7 +135,7 @@                     [ PName "CO2"                     , PmType Quantitative                     , PScale [ SZero False ]-                    , PAxis [ AxTitle "CO2 concentration in ppm" ]+                    , PAxis [ AxTitle "CO₂ concentration in ppm" ]                     ]          encLine =@@ -151,12 +171,10 @@         specTextMax =             asSpec [ transTextMax [], mark Text [ MAlign AlignLeft, MBaseline AlignBottom, MdX 3, MdY 1 ], encTextMax [] ] -        config =-            configure . configuration (View [ ViewStroke Nothing ])     in     toVegaLite         [ des-        , config []+        , noStroke []         , width 800         , height 500         , dataFromUrl "https://vega.github.io/vega-lite/data/co2-concentration.csv" [ Parse [ ( "Date", FoUtc "%Y-%m-%d" ) ] ]@@ -328,3 +346,443 @@             asSpec [ mark Point [], encPopulation [] ]     in     toVegaLite [ des, width 500, dvals [], layer [ specRects, specLine, specPoints ] ]+++label8 :: VegaLite+label8 =+  let strColumn n vs = dataColumn n (Strings vs)++      medians =+        dataFromColumns []+        . strColumn "name" [ "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:" ]+        . dataColumn "median" (Numbers [ 1.999976, 2, 1.999969, 2.500045, 1.500022, 2.99998, 4.500007 ])+        . strColumn "lo" [ "Easy", "Easy", "Toolbar", "Toolbar", "Toolbar", "Toolbar", "Phone" ]+        . strColumn "hi" [ "Hard", "Hard", "Gesture", "Gesture", "Gesture", "Gesture", "Tablet" ]++      values =+        dataFromColumns []+        . strColumn "value" [ "P1", "2", "2", "3", "4", "2", "5", "5", "1", "1", "P2", "2", "3", "4", "5", "5", "5", "5", "1", "1", "P3", "2", "2", "2", "1", "2", "1", "5", "1", "0", "P4", "3", "3", "2", "2", "4", "1", "5", "1", "0", "P5", "2", "2", "4", "4", "4", "5", "5", "0", "1", "P6", "1", "3", "3", "4", "4", "4", "4", "0", "1", "P7", "2", "3", "4", "5", "3", "2", "4", "0", "0", "P8", "3", "1", "2", "4", "2", "5", "5", "0", "0", "P9", "2", "3", "2", "4", "1", "4", "4", "1", "1", "P10", "2", "2", "1", "1", "1", "1", "5", "1", "1", "P11", "2", "2", "1", "1", "1", "1", "4", "1", "0", "P12", "1", "3", "2", "3", "1", "3", "3", "0", "1", "P13", "2", "2", "1", "1", "1", "1", "5", "0", "0", "P14", "3", "3", "2", "2", "1", "1", "1", "1", "1", "P15", "4", "5", "1", "1", "1", "1", "5", "1", "0", "P16", "1", "3", "2", "2", "1", "4", "5", "0", "1", "P17", "3", "2", "2", "2", "1", "3", "2", "0", "0" ]+        . strColumn "name" [ "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First", "Participant ID", "Identify Errors:", "Fix Errors:", "Easier to Fix:", "Faster to Fix:", "Easier on Phone:", "Easier on Tablet:", "Device Preference:", "Tablet_First", "Toolbar_First" ]+        . strColumn "id" [ "P1", "P1", "P1", "P1", "P1", "P1", "P1", "P1", "P1", "P1", "P2", "P2", "P2", "P2", "P2", "P2", "P2", "P2", "P2", "P2", "P3", "P3", "P3", "P3", "P3", "P3", "P3", "P3", "P3", "P3", "P4", "P4", "P4", "P4", "P4", "P4", "P4", "P4", "P4", "P4", "P5", "P5", "P5", "P5", "P5", "P5", "P5", "P5", "P5", "P5", "P6", "P6", "P6", "P6", "P6", "P6", "P6", "P6", "P6", "P6", "P7", "P7", "P7", "P7", "P7", "P7", "P7", "P7", "P7", "P7", "P8", "P8", "P8", "P8", "P8", "P8", "P8", "P8", "P8", "P8", "P9", "P9", "P9", "P9", "P9", "P9", "P9", "P9", "P9", "P9", "P10", "P10", "P10", "P10", "P10", "P10", "P10", "P10", "P10", "P10", "P11", "P11", "P11", "P11", "P11", "P11", "P11", "P11", "P11", "P11", "P12", "P12", "P12", "P12", "P12", "P12", "P12", "P12", "P12", "P12", "P13", "P13", "P13", "P13", "P13", "P13", "P13", "P13", "P13", "P13", "P14", "P14", "P14", "P14", "P14", "P14", "P14", "P14", "P14", "P14", "P15", "P15", "P15", "P15", "P15", "P15", "P15", "P15", "P15", "P15", "P16", "P16", "P16", "P16", "P16", "P16", "P16", "P16", "P16", "P16", "P17", "P17", "P17", "P17", "P17", "P17", "P17", "P17", "P17", "P17" ]++      enc = encoding+            . position Y [ PName "name"+                         , PmType Nominal+                         , PSort []+                         , PAxis+                           [ AxDomain False+                           , AxOffset 50+                           , AxLabelFontWeight Bold+                           , AxTicks False+                           , AxGrid True+                           , AxNoTitle+                           ]+                         ]++      trans = transform+              . filter (FExpr "datum.name != 'Toolbar_First'")+              . filter (FExpr "datum.name != 'Tablet_First'")+              . filter (FExpr "datum.name != 'Participant ID'")++      encCircle =+        encoding+        . position X [ PName "value"+                     , PmType Quantitative+                     , PScale [ SDomain (DNumbers [ 0, 6 ]) ]+                     , PAxis [ AxGrid False, AxValues (Numbers [ 1, 2, 3, 4, 5 ]) ]+                     ]+        . size [ MAggregate Count+               , MmType Quantitative+               , MLegend [ LTitle "Number of Ratings", LOffset 75 ]+               ]++      specCircle =+        asSpec [ dataFromSource "values" []+               , trans []+               , encCircle []+               , mark Circle [ MColor "#6eb4fd" ]+               ]++      encTick1 =+        encoding+        . position X [ PName "median"+                     , PmType Quantitative+                     , PScale [ SDomain (DNumbers [ 0, 6 ]) ]+                     , PAxis [ AxNoTitle ]+                     ]++      specTick1 =+        asSpec [ encTick1 [], mark Tick [ MColor "black" ] ]++      encTextLo =+        encoding+        . text [ TName "lo", TmType Nominal ]++      specTextLo =+        asSpec [ encTextLo [], mark Text [ MX (-5), MAlign AlignRight ] ]++      encTextHi =+        encoding+        . text [ TName "hi", TmType Nominal ]++      specTextHi =+        asSpec [ encTextHi [], mark Text [ MX 255, MAlign AlignLeft ] ]++  in toVegaLite+        [ noStroke []+        , datasets [ ( "medians", medians [] ), ( "values", values [] ) ]+        , dataFromSource "medians" []+        , title "Questionnaire Ratings" []+        , width 250+        , height 175+        , enc []+        , layer [ specCircle, specTick1, specTextLo, specTextHi ]+        ]+++label9 :: VegaLite+label9 =+  let des = description "Comparing Likert scale ratings between two conditions."++      cfg = noStroke+            . configuration+                    (MarkNamedStyles+                        [ ( "arrow-label", [ MdY 12, MFontSize 9.5 ] )+                        , ( "arrow-label2", [ MdY 24, MFontSize 9.5 ] )+                        ]+                    )+            . configuration (TitleStyle [ TFontSize 12 ])++      lickertData =+        dataFromColumns []+        . dataColumn "measure" (Strings [ "Open Exploration", "Focused Question Answering", "Open Exploration", "Focused Question Answering" ])+        . dataColumn "mean" (Numbers [ 1.81, -1.69, 2.19, -0.06 ])+        . dataColumn "lo" (Numbers [ 1.26, -2.33, 1.67, -0.47 ])+        . dataColumn "hi" (Numbers [ 2.37, -1.05, 2.71, 0.35 ])+        . dataColumn "study" (Strings [ "PoleStar vs Voyager", "PoleStar vs Voyager", "PoleStar vs Voyager 2", "PoleStar vs Voyager 2" ])++      labelData =+        dataFromColumns []+        . dataColumn "from" (Numbers [ -0.25, 0.25 ])+        . dataColumn "to" (Numbers [ -2.9, 2.9 ])+        . dataColumn "label" (Strings [ "PoleStar", "Voyager / Voyager 2" ])++      encLickert =+        encoding+        . position Y [ PName "study"+                     , PmType Nominal+                     , PAxis [ AxNoTitle+                             , AxLabelPadding 5+                             , AxDomain False+                             , AxTicks False+                             , AxGrid False+                             ]+                     ]++      encLickertWhiskers =+        encoding+        . position X [ PName "lo"+                     , PmType Quantitative+                     , PScale [ SDomain (DNumbers [ -3, 3 ]) ]+                     , PAxis+                       [ AxNoTitle+                       , AxGridDash [ 3, 3 ]+                       , AxDataCondition (Expr "datum.value === 0") (CAxGridColor "#666" "#ccc")+                       ]+                     ]+        . position X2 [ PName "hi" ]++      specLickertWhiskers = asSpec [ encLickertWhiskers [], mark Rule [] ]++      encLickertMeans =+        encoding+        . position X [ PName "mean", PmType Quantitative ]+        . color [ MName "measure"+                , MmType Nominal+                , MScale [ SRange (RStrings [ "black", "white" ]) ]+                , MLegend []+                ]++      specLickertMeans =+        asSpec [ encLickertMeans [], mark Circle [ MStroke "black", MOpacity 1 ] ]++      specLickert =+        asSpec+        [ title "Mean of Subject Ratings (95% CIs)" [ TFrame FrBounds ]+        , encLickert []+        , layer [ specLickertWhiskers, specLickertMeans ]+        ]++      encLabel1 =+        encoding+        . position X [ PName "from", PmType Quantitative, PScale [ SZero False ], PAxis [] ]+        . position X2 [ PName "to" ]++      specLabel1 = asSpec [ encLabel1 [], mark Rule [] ]++      encLabel2 =+        encoding+        . position X [ PName "to", PmType Quantitative, PAxis [] ]+        . shape [ MDataCondition+                  [ ( Expr "datum.to > 0", [ MSymbol SymTriangleRight ] ) ]+                  [ MSymbol SymTriangleLeft ]+                ]++      specLabel2 = asSpec [ encLabel2 [], mark Point [ MFilled True, MSize 60, MFill "black" ] ]++      transLabel3 =+        transform+        . filter (FExpr "datum.label === 'PoleStar'")++      from = position X [ PName "from", PmType Quantitative, PAxis [] ]++      encLabel3 =+        encoding+        . from+        . text [ TName "label", TmType Nominal ]++      specLabel3 =+        asSpec [ transLabel3 []+               , encLabel3 []+               , mark Text [ MAlign AlignRight, MStyle [ "arrow-label" ] ]+               ]++      transLabel4 =+        transform+        . filter (FExpr "datum.label !== 'PoleStar'")++      encLabel4 = encLabel3++      specLabel4 =+        asSpec [ transLabel4 []+               , encLabel4 []+               , mark Text [ MAlign AlignLeft, MStyle [ "arrow-label" ] ]+               ]++      transLabel5 = transLabel3++      encLabel5 =+        encoding+        . from+        . text [ TString "more valuable" ]++      specLabel5 =+        asSpec [ transLabel5 []+               , encLabel5 []+               , mark Text [ MAlign AlignRight, MStyle [ "arrow-label2" ] ]+               ]++      transLabel6 = transLabel4++      encLabel6 = encLabel5++      specLabel6 =+        asSpec [ transLabel6 []+               , encLabel6 []+               , mark Text [ MAlign AlignLeft, MStyle [ "arrow-label2" ] ]+               ]++      specLabels =+        asSpec [ labelData []+               , layer [ specLabel1, specLabel2, specLabel3, specLabel4, specLabel5, specLabel6 ]+               ]++  in toVegaLite [ des+                , cfg []+                , lickertData []+                , spacing 10+                , vConcat [ specLickert, specLabels ]+                ]++-- like label9 but trying to match the current version (Feb 2020) of+-- https://vega.github.io/vega-lite/examples/concat_layer_voyager_result.html+--+voyagerData :: Value+voyagerData = [aesonQQ|+[ { "measure": "Open Exploration",+    "mean": 1.813,+    "lo": 1.255,+    "hi": 2.37,+    "study": "PoleStar vs Voyager"+  },+  {+    "measure": "Focused Question Answering",+    "mean": -1.688,+    "lo": -2.325,+    "hi": -1.05,+    "study": "PoleStar vs Voyager"+  },+  {+    "measure": "Open Exploration",+    "mean": 2.1875,+    "lo": 1.665,+    "hi": 2.71,+    "study": "PoleStar vs Voyager 2"+  },+  {+    "measure": "Focused Question Answering",+    "mean": -0.0625,+    "lo": -0.474,+    "hi": 0.349,+    "study": "PoleStar vs Voyager 2"+  } ]+|]++voyager :: VegaLite+voyager =+  let dataPlot = [ title "Mean of Subject Ratings (95% CIs)" [TFrame FrBounds]+                 , encoding+                   . position Y [ PName "study"+                                , PmType Nominal+                                , PAxis [ AxNoTitle+                                        , AxLabelPadding 5+                                        , AxDomain False+                                        , AxTicks False+                                        , AxGrid False+                                        ]+                                ]+                   $ []+                 , layer [asSpec rulePlot, asSpec circlePlot]+                 ]++      gridColor = AxDataCondition (Expr "datum.value === 0")+                                  (CAxGridColor "#666" "#CCC")++      rulePlot = [ mark Rule []+                 , encoding+                   . position X [ PName "lo"+                                , PmType Quantitative+                                , PScale [SDomain (DNumbers [-3, 3])]+                                , PAxis [ AxTitle ""+                                        , AxGridDash [3, 3]+                                        , gridColor+                                        ]+                                ]+                   . position X2 [PName "hi"]+                   $ []+                 ]++      circlePlot = [ mark Circle [MStroke "black", MOpacity 1]+                   , encoding+                     . position X [PName "mean", PmType Quantitative]+                     . color [ MName "measure"+                             , MmType Nominal+                             , MScale [SRange (RStrings ["black", "white"])]+                             , MLegend []+                             ]+                     $ []+                   ]++      labelPlot = [ dataFromColumns []+                    . dataColumn "from" (Numbers [-0.25, 0.25])+                    . dataColumn "to" (Numbers [-2.9, 2.9])+                    . dataColumn "label" (Strings ["PoleStar", "Voyager / Voyager 2"])+                    $ []+                  , layer (map asSpec [linePlot, arrowsPlot, pTextPlot, vTextPlot])+                  ]++      linePlot = [ mark Rule []+                 , encoding+                   . position X [ PName "from"+                                , PmType Quantitative+                                , PScale [SZero False]+                                , PAxis []+                                ]+                   . position X2 [PName "to"]+                   $ []+                 ]++      shapeOpts = MDataCondition+                      [(Expr "datum.to > 0", [MSymbol SymTriangleRight])]+                      [MSymbol SymTriangleLeft]++      arrowsPlot = [ mark Point [ MFilled True+                                , MFill "black"+                                , MSize 60 ]+                   , encoding+                     . position X [ PName "to"+                                  , PmType Quantitative+                                  , PAxis []+                                  ]+                     . shape [ shapeOpts ]+                     $ []+                   ]++      from = position X [PName "from", PmType Quantitative, PAxis []]++      pTextPlot = [ mark Text [ MAlign AlignRight+                              , MStyle ["arrow-label"]+                              , MTexts ["Polestar", "More Valuable"]+                              ]+                  , transform+                    . filter (FExpr "datum.label === 'PoleStar'")+                    $ []+                  , encoding+                    . from+                    $ []+                  ]++      vTextPlot = [ mark Text [ MAlign AlignLeft+                              , MStyle ["arrow-label"]+                              , MTexts ["Voyager / Voyager 2", "More Valuable"]+                              ]+                  , transform+                    . filter (FExpr "datum.label !== 'PoleStar'")+                    $ []+                  , encoding+                    . from+                    $ []+                  ]++      styles = MarkNamedStyles+                   [ ("arrow-label", [MdY 12, MFontSize 9.5])+                   , ("arrow-label2", [MdY 24, MFontSize 9.5])+                   ]+      conf = configure+             . configuration (ViewStyle [ViewStroke "transparent"])+             . configuration styles+             . configuration (TitleStyle [TFontSize 12])++      v = [ dataFromJson voyagerData []+          , spacing 10+          , vConcat [asSpec dataPlot, asSpec labelPlot]+          , conf []+          ]++  in toVegaLite v+++baselines :: VegaLite+baselines =+  let dvals = dataFromColumns []+              . dataColumn "x" (Numbers [ 10, 20 ])+              . dataColumn "y" (Numbers [ 10, 20 ])++      ax t n = position t [ PName n+                          , PmType Quantitative+                          , PScale [ SNice (IsNice False)+                                   , SDomain (DNumbers [5, 25])+                                   ]+                          , PAxis [ AxNoTitle ]+                          ]++      enc = encoding+            . ax X "x"+            . ax Y "y"+            . text [ TString "Xxgq" ]++      plot l a = asSpec [ enc [], title l [], mark Text [ MBaseline a ] ]++      plots = vlConcat [ plot "top" AlignTop+                       , plot "middle" AlignMiddle+                       , plot "baseline" AlignBaseline+                       , plot "bottom" AlignBottom+                       ]++  in toVegaLite [ dvals []+                , configure+                  . configuration (MarkStyle [ MFontSize 20 ])+                  $ []+                , columns 2+                , plots+                ]
tests/Gallery/Layer.hs view
@@ -293,100 +293,66 @@  layer6 :: VegaLite layer6 =-    let-        enc1 =-            encoding-                . position Y [ PName "record.low", PmType Quantitative, PScale [ SDomain (DNumbers [ 10, 70 ]) ], PAxis [ AxTitle "Temperature (F)" ] ]-                . position Y2 [ PName "record.high" ]-                . position X [ PName "id", PmType Ordinal, PAxis [ AxTitle "Day" ] ]-                . size [ MNumber 20 ]-                . color [ MString "#ccc" ]--        spec1 =-            asSpec [ mark Bar [], enc1 [] ]+  let label = description "A layered bar chart with floating bars representing weekly weather data"+      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/weather.json" [] -        enc2 =-            encoding-                . position Y [ PName "normal.low", PmType Quantitative ]-                . position Y2 [ PName "normal.high" ]-                . position X [ PName "id", PmType Ordinal ]-                . size [ MNumber 20 ]-                . color [ MString "#999" ]+      titleOpts = title "Weekly Weather\nObservations and Predictions" [TFrame FrGroup] -        spec2 =-            asSpec [ mark Bar [], enc2 [] ]+      axis1 = [AxDomain False, AxTicks False, AxLabels False, AxNoTitle, AxTitlePadding 25, AxOrient STop]+      enc = encoding (position X [PName "id", PmType Ordinal, PAxis axis1] []) -        enc3 =-            encoding-                . position Y [ PName "actual.low", PmType Quantitative ]-                . position Y2 [ PName "actual.high" ]-                . position X [ PName "id", PmType Ordinal ]-                . size [ MNumber 12 ]-                . color [ MString "#000" ]+      enc1 = encoding+             . position Y [ PName "record.low", PmType Quantitative+                          , PScale [SDomain (DNumbers [10, 70])]+                          , PAxis [AxTitle "Temperature (F)"]+                          ]+             . position Y2 [PName "record.high"]+             . size [MNumber 20]+             . color [MString "#ccc"]+      lyr1 = [mark Bar [MStyle ["box"]], enc1 []] -        spec3 =-            asSpec [ mark Bar [], enc3 [] ]+      enc2 = encoding+             . position Y [PName "normal.low", PmType Quantitative]+             . position Y2 [PName "normal.high"]+             . size [MNumber 20]+             . color [MString "#999"]+      lyr2 = [mark Bar [MStyle ["box"]], enc2 []] -        enc4 =-            encoding-                . position Y [ PName "forecast.low.low", PmType Quantitative ]-                . position Y2 [ PName "forecast.low.high" ]-                . position X [ PName "id", PmType Ordinal ]-                . size [ MNumber 12 ]-                . color [ MString "#000" ]+      enc3 = encoding+             . position Y [PName "actual.low", PmType Quantitative]+             . position Y2 [PName "actual.high"]+             . size [MNumber 12]+             . color [MString "#000"]+      lyr3 = [mark Bar [MStyle ["box"]], enc3 []] -        spec4 =-            asSpec [ mark Bar [], enc4 [] ]+      enc4 = encoding+             . position Y [PName "forecast.low.low", PmType Quantitative]+             . position Y2 [PName "forecast.low.high"]+             . size [MNumber 12]+             . color [MString "#000"]+      lyr4 = [mark Bar [MStyle ["box"]], enc4 []] -        enc5 =-            encoding-                . position Y [ PName "forecast.low.high", PmType Quantitative ]-                . position Y2 [ PName "forecast.high.low" ]-                . position X [ PName "id", PmType Ordinal ]-                . size [ MNumber 3 ]-                . color [ MString "#000" ]+      enc5 = encoding+             . position Y [PName "forecast.low.high", PmType Quantitative]+             . position Y2 [PName "forecast.high.low"]+             . size [MNumber 3]+             . color [MString "#000"]+      lyr5 = [mark Bar [MStyle ["box"]], enc5 []] -        spec5 =-            asSpec [ mark Bar [], enc5 [] ]+      enc6 = encoding+             . position Y [PName "forecast.high.low", PmType Quantitative]+             . position Y2 [PName "forecast.high.high"]+             . size [MNumber 12]+             . color [MString "#000"]+      lyr6 = [mark Bar [MStyle ["box"]], enc6 []] -        enc6 =-            encoding-                . position Y [ PName "forecast.high.low", PmType Quantitative ]-                . position Y2 [ PName "forecast.high.high" ]-                . position X [ PName "id", PmType Ordinal ]-                . size [ MNumber 12 ]-                . color [ MString "#000" ]+      enc7 = encoding (text [TName "day", TmType Nominal] [])+      lyr7 = [mark Text [MAlign AlignCenter, MBaseline AlignBottom, MY (-5)], enc7] -        spec6 =-            asSpec [ mark Bar [], enc6 [] ]+      lyr = layer (map asSpec [lyr1, lyr2, lyr3, lyr4, lyr5, lyr6, lyr7]) -        enc7 =-            encoding-                . position X-                    [ PName "id"-                    , PmType Ordinal-                    , PAxis-                        [ AxDomain False-                        , AxTicks False-                        , AxLabels False-                        , AxTitle "Day"-                        , AxTitlePadding 25-                        , AxOrient STop-                        ]-                    ]-                . text [ TName "day", TmType Nominal ]+  in toVegaLite [label, titleOpts, dvals, width 250, height 200, enc, lyr] -        spec7 =-            asSpec [ mark Text [ MAlign AlignCenter, MdY (-105) ], enc7 [] ]-    in-    toVegaLite-        [ description "A layered bar chart with floating bars representing weekly weather data"-        , title "Weekly Weather Observations and Predictions" []-        , width 250-        , height 200-        , dataFromUrl "https://vega.github.io/vega-lite/data/weather.json" []-        , layer [ spec1, spec2, spec3, spec4, spec5, spec6, spec7 ]-        ]   -- From
tests/Gallery/Line.hs view
@@ -291,7 +291,7 @@             asSpec [ transTextMax [], mark Text [ MAlign AlignLeft, MBaseline AlignBottom, MdX 3, MdY 1 ], encTextMax [] ]          config =-            configure . configuration (View [ ViewStroke Nothing ])+            configure . configuration (ViewStyle [ ViewNoStroke ])     in     toVegaLite         [ des
tests/Gallery/Multi.hs view
@@ -176,12 +176,17 @@                 . position X [ PName "IMDB_Rating", PmType Quantitative, PBin [ MaxBins 10 ] ]                 . position Y [ PName "Rotten_Tomatoes_Rating", PmType Quantitative, PBin [ MaxBins 10 ] ] +        colLegend = [ LTitle "All Movies"+                    , LDirection Horizontal+                    , LGradientLength 120+                    ]         enc1 =             encoding-                . color [ MAggregate Count, MmType Quantitative, MLegend [ LNoTitle ] ]+                . color [ MAggregate Count, MmType Quantitative, MLegend colLegend ] +        -- removed width as not valid in Vega-Lite 4.1.1         spec1 =-            asSpec [ width 300, mark Rect [], enc1 [] ]+            asSpec [ {- width 300, -} mark Rect [], enc1 [] ]          enc2 =             encoding@@ -198,7 +203,7 @@             selection . select "myPts" Single [ Encodings [ ChX ] ]          barSpec =-            asSpec [ width 420, height 120, mark Bar [], sel [], encBar [] ]+            asSpec [ width 330, height 120, mark Bar [], sel [], encBar [] ]          encBar =             encoding@@ -211,7 +216,7 @@                     ]          config =-            configure . configuration (Range [ RHeatmap "greenblue" ])+            configure . configuration (RangeStyle [ RHeatmap "greenblue" ])          res =             resolve@@ -376,7 +381,7 @@          cfg =             configure-                . configuration (View [ ViewStroke Nothing ])+                . configuration (ViewStyle [ ViewNoStroke ])     in     toVegaLite         [ desc, cfg [], dvals [], trans [], res [], hConcat [ specPoint, specHPText, specMPGText, specOriginText ] ]@@ -387,7 +392,7 @@   let des = description "One dot per airport in the US overlayed on geoshape"        cfg = configure-            . configuration (View [ ViewStroke Nothing ])+            . configuration (ViewStyle [ ViewNoStroke ])        backdropSpec =         asSpec
tests/Gallery/Repeat.hs view
@@ -176,8 +176,8 @@          config =             configure-                . configuration (Range [ RHeatmap "greenblue" ])-                . configuration (View [ ViewStroke Nothing ])+                . configuration (RangeStyle [ RHeatmap "greenblue" ])+                . configuration (ViewStyle [ ViewNoStroke ])          enc1 =             encoding
tests/Gallery/Table.hs view
@@ -49,7 +49,7 @@          conf =             configure-                . configuration (View [ ViewStrokeWidth 0, ViewStep 13 ])+                . configuration (ViewStyle [ ViewStrokeWidth 0, ViewStep 13 ])                 . configuration (Axis [ Domain False ])          enc =@@ -94,8 +94,8 @@          config =             configure-                . configuration (Range [ RHeatmap "greenblue" ])-                . configuration (View [ ViewStroke Nothing ])+                . configuration (RangeStyle [ RHeatmap "greenblue" ])+                . configuration (ViewStyle [ ViewNoStroke ])     in     toVegaLite         [ des@@ -157,7 +157,7 @@          config =             configure-                . configuration (Scale [ SCBandPaddingInner 0, SCBandPaddingOuter 0 ])+                . configuration (ScaleStyle [ SCBandPaddingInner 0, SCBandPaddingOuter 0 ])                 . configuration (TextStyle [ MBaseline AlignMiddle ])     in     toVegaLite
tests/GeoTests.hs view
@@ -51,6 +51,10 @@ -}  +noStroke :: PropertySpec+noStroke = configure $ configuration (ViewStyle [ ViewNoStroke ]) []++ defaultSize1 :: VegaLite defaultSize1 =     toVegaLite@@ -66,8 +70,8 @@ defaultSize2 =     toVegaLite         [ description "Default map size with view width and height specified in config."-        , configure $ configuration (View [ ViewContinuousWidth 500-                                          , ViewContinuousHeight 300 ]) []+        , configure $ configuration (ViewStyle [ ViewContinuousWidth 500+                                               , ViewContinuousHeight 300 ]) []         , projection [ PrType AlbersUsa ]         , dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "counties" ]         , mark Geoshape []@@ -80,7 +84,7 @@     toVegaLite         [ width 900         , height 500-        , configure $ configuration (View [ ViewStroke Nothing ]) []+        , noStroke         , dataFromUrl "https://vega.github.io/vega-lite/data/londonBoroughs.json" [ TopojsonFeature "boroughs" ]         , mark Geoshape [ MStrokeOpacity 0 ]         , encoding $ color [ MName "id", MmType Nominal ] []@@ -118,7 +122,7 @@     toVegaLite         [ width 1200         , height 700-        , configure $ configuration (View [ ViewStroke Nothing ]) []+        , noStroke         , layer [ polySpec, labelSpec ]         ] @@ -149,7 +153,7 @@     toVegaLite         [ width 700         , height 500-        , configure $ configuration (View [ ViewStroke Nothing ]) []+        , noStroke         , dataFromUrl "https://vega.github.io/vega-lite/data/londonTubeLines.json" [ TopojsonFeature "line" ]         , mark Geoshape [ MFilled False, MStrokeWidth 2 ]         , enc []@@ -199,7 +203,7 @@     toVegaLite         [ width 700         , height 500-        , configure $ configuration (View [ ViewStroke Nothing ]) []+        , noStroke         , layer [ polySpec, labelSpec, routeSpec ]         ] @@ -446,7 +450,7 @@             asSpec [ width 300, height 300, projection [ PrType Orthographic ], layer [ graticuleSpec, countrySpec ] ]     in     toVegaLite-        [ configure $ configuration (View [ ViewStroke Nothing ]) []+        [ noStroke         , hConcat [ globe, globe, globe ]         ] @@ -458,27 +462,23 @@             let                 graticuleSpec =                     asSpec-                        [ width 300-                        , height 300-                        , projection [ PrType Orthographic, PrRotate rot 0 0 ]+                        [ projection [ PrType Orthographic, PrRotate rot 0 0 ]                         , dataFromUrl "https://vega.github.io/vega-lite/data/graticule.json" [ TopojsonFeature "graticule" ]                         , mark Geoshape [ MFilled False, MStroke "#411", MStrokeWidth 0.1 ]                         ]                  countrySpec =                     asSpec-                        [ width 300-                        , height 300-                        , projection [ PrType Orthographic, PrRotate rot 0 0 ]+                        [ projection [ PrType Orthographic, PrRotate rot 0 0 ]                         , dataFromUrl "https://vega.github.io/vega-lite/data/world-110m.json" [ TopojsonFeature "countries" ]                         , mark Geoshape [ MStroke "white", MFill "black", MStrokeWidth 0.5 ]                         ]             in-            asSpec [ layer [ graticuleSpec, countrySpec ] ]+            asSpec [ width 300, height 300, layer [ graticuleSpec, countrySpec ] ]     in     toVegaLite-        [ configure $ configuration (View [ ViewStroke Nothing ]) []-        , hConcat [ rotatedSpec (-65), rotatedSpec 115, rotatedSpec (-65) ]+        [ noStroke+        , hConcat [ rotatedSpec (-65), rotatedSpec 115, rotatedSpec 10 ]         ]  @@ -489,35 +489,29 @@             let                 seaSpec =                     asSpec-                        [ width 300-                        , height 300-                        , projection [ PrType Orthographic, PrRotate 0 0 0 ]+                        [ projection [ PrType Orthographic, PrRotate 0 0 0 ]                         , dataFromUrl "data/globe.json" [ TopojsonFeature "globe" ]                         , mark Geoshape [ MFill "#c1e7f5", MStrokeOpacity 0 ]                         ]                  graticuleSpec =                     asSpec-                        [ width 300-                        , height 300-                        , projection [ PrType Orthographic, PrRotate rot 0 0 ]+                        [ projection [ PrType Orthographic, PrRotate rot 0 0 ]                         , dataFromUrl "https://vega.github.io/vega-lite/data/graticule.json" [ TopojsonFeature "graticule" ]                         , mark Geoshape [ MFilled False, MStroke "#411", MStrokeWidth 0.1 ]                         ]                  countrySpec =                     asSpec-                        [ width 300-                        , height 300-                        , projection [ PrType Orthographic, PrRotate rot 0 0 ]+                        [ projection [ PrType Orthographic, PrRotate rot 0 0 ]                         , dataFromUrl "https://vega.github.io/vega-lite/data/world-110m.json" [ TopojsonFeature "countries" ]                         , mark Geoshape [ MStroke "white", MFill "#242", MStrokeWidth 0.1 ]                         ]             in-            asSpec [ layer [ seaSpec, graticuleSpec, countrySpec ] ]+            asSpec [ width 300, height 300, layer [ seaSpec, graticuleSpec, countrySpec ] ]     in     toVegaLite-        [ configure $ configuration (View [ ViewStroke Nothing ]) []+        [ noStroke         , hConcat [ rotatedSpec 0, rotatedSpec (-40) ]         ] @@ -554,7 +548,7 @@         config =             configure                 . configuration (TitleStyle [ TFont "Roboto", TFontWeight W300, TFontSize 28 ])-                . configuration (View [ ViewStroke Nothing ])+                . configuration (ViewStyle [ ViewNoStroke ])          trans =             transform@@ -591,7 +585,7 @@         config =             configure                 . configuration (TitleStyle [ TFont "Roboto", TFontWeight W300, TFontSize 28 ])-                . configuration (View [ ViewStroke Nothing ])+                . configuration (ViewStyle [ ViewNoStroke ])          trans =             transform
tests/InteractionTests.hs view
@@ -29,6 +29,8 @@             , ("bindlegend2", bindLegendDouble)             , ("bindlegendboth", bindLegendBoth)             , ("lookupSelection1", lookupSelection1)+            , ("curpointer", curPointer)+            , ("curhelp", curHelp)             ]  @@ -250,13 +252,16 @@ -- lookup into a selection -- based on https://vega.github.io/vega-lite/docs/lookup.html#lookup-selection ---lookupSelection1 :: VegaLite-lookupSelection1 =-  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv"++csvStocks :: Data+csvStocks = dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv"                  [ CSV, Parse [("date", FoDate "")] ] -      xaxis = position X [PName "date", PmType Temporal, PAxis []] +lookupSelection1 :: VegaLite+lookupSelection1 =+  let xaxis = position X [PName "date", PmType Temporal, PAxis []]+       t0 = DateTime [DTYear 2005, DTMonthNum 1, DTDate 1]       selPoint = selection                  . select "index" Single@@ -306,8 +311,42 @@       layers = layer (map asSpec [pointSpec, lineSpec, ruleSpec])    in toVegaLite-     [ dvals+     [ csvStocks      , width 650      , height 300      , layers      ]+++showCursor :: Cursor -> VegaLite+showCursor cur =+  let cfg = configure+            . configuration (ViewStyle [ ViewCursor CText ])++      trans = transform+              . filter (FExpr "datum.symbol==='GOOG'")++      sel = selection+            . select "myBrush"+                     Interval+                     [ Encodings [ ChX ]+                     , SelectionMark [ SMCursor cur ]+                     ]++      encLine = encoding+                . position X [PName "date", PmType Temporal]+                . position Y [PName "price", PmType Quantitative]++  in toVegaLite [ width 400+                , cfg []+                , csvStocks+                , trans []+                , sel []+                , encLine []+                , mark Line []+                ]+++curPointer, curHelp :: VegaLite+curPointer = showCursor CPointer+curHelp = showCursor CHelp
tests/LegendTests.hs view
@@ -24,43 +24,59 @@             , ("legend11d", legend11direct)             , ("corners1", corners1)             , ("corners2", corners2)+            , ("limits1", limits 1)+            , ("limits2", limits 2)+            , ("limits3", limits 3)             ] ++carsData :: Data+carsData = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []+++xHorse, yMPG :: BuildEncodingSpecs+xHorse = position X [ PName "Horsepower", PmType Quantitative ]+yMPG = position Y [ PName "Miles_per_Gallon", PmType Quantitative ]+++-- here we don't want [] to mean "no legend"+noNull :: [LegendProperty] -> [MarkChannel]+noNull [] = []+noNull lps = [MLegend lps]++origin, hp, weight :: [LegendProperty] -> [MarkChannel]+origin lps = noNull lps ++ [ MName "Origin", MmType Nominal ]+hp lps = noNull lps ++ [ MName "Horsepower", MmType Quantitative ]+weight lps = noNull lps ++ [ MName "Weight_in_lbs", MmType Quantitative ]++ legendCore :: [LegendProperty] -> VegaLite legendCore legProps =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"+  let enc = encoding+            . xHorse+            . yMPG+            . color (origin legProps)+            . size (hp legProps)+            . opacity (weight legProps) -        enc =-            encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]-                . color [ MName "Origin", MmType Nominal, MLegend legProps ]-                . size [ MName "Horsepower", MmType Quantitative, MLegend legProps ]-                . opacity [ MName "Weight_in_lbs", MmType Quantitative, MLegend legProps ]-    in-    toVegaLite [ width 300, height 300, dataVals [], enc [], mark Circle [] ]+  in toVegaLite [ width 300, height 300, carsData, enc [], mark Circle [] ] + legendCoreCfg :: [LegendConfig] -> VegaLite legendCoreCfg cfg =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"--        enc =+    let enc =             encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]+                . xHorse+                . yMPG                 . color [ MName "Origin", MmType Nominal ]                 . size [ MName "Horsepower", MmType Quantitative ]                 . opacity [ MName "Weight_in_lbs", MmType Quantitative ]     in     toVegaLite-        [ (configure . configuration (Legend cfg)) []+        [ (configure . configuration (LegendStyle cfg)) []         , width 300         , height 300-        , dataVals []+        , carsData         , enc []         , mark Circle []         ]@@ -94,18 +110,14 @@  legend10 :: VegaLite legend10 =-    let-        dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"--        enc =+    let enc =             encoding-                . position X [ PName "Horsepower", PmType Quantitative ]-                . position Y [ PName "Miles_per_Gallon", PmType Quantitative ]+                . xHorse+                . yMPG                 . color [ MName "Origin", MmType Nominal,                           MLegend [ LOrient LONone, LeX 232, LeY 5 ] ]     in-    toVegaLite [ width 300, height 300, dataVals [], enc [], mark Circle [] ]+    toVegaLite [ width 300, height 300, carsData, enc [], mark Circle [] ]  -- change a number of items using the legend configure legend11 :: VegaLite@@ -184,3 +196,32 @@         , LLabelAlign AlignRight         , LLabelOverlap OGreedy         ]+++-- trying to combine symbollimit and unselectedopacity+limits :: Int -> VegaLite+limits n =+  let enc = encoding+            . xHorse+            . yMPG+            . shape (origin [])+            . color (origin [])+            . size [ MSelectionCondition (SelectionName "sel")+                     [ MNumber 100 ]+                     [ MNumber 20 ]+                   ]++      cfg = [ LeSymbolLimit n+            , LeUnselectedOpacity 0.1 ]++      selOpts = [ On "click"+                , BindLegend (BLFieldEvent "Origin" "dblclick") ]++  in toVegaLite [ width 300+                , height 300+                , configure (configuration (LegendStyle cfg) [])+                , selection (select "sel" Multi selOpts [])+                , carsData+                , enc []+                , mark Point [MFilled True]+                ]
tests/PositionTests.hs view
@@ -25,6 +25,11 @@             , ("position10", position10)             , ("position11", position11)             , ("position12", position12)+            , ("position8r", position8r)+            , ("position9r", position9r)+            , ("position10r", position10r)+            , ("position11r", position11r)+            , ("position12r", position12r)             ]  @@ -44,10 +49,11 @@     dataFromColumns []         . dataColumn "empty" (Numbers [0]) +-- make sure this is not symmetric in x someData =     dataFromColumns []         . dataColumn "cat" (Numbers [1, 2, 3, 4, 5])-        . dataColumn "val" (Numbers [10, 20, 30, 20, 10])+        . dataColumn "val" (Numbers [10, 20, 30, 15, 12])         . dataColumn "empty" (Numbers [0])  @@ -102,24 +108,39 @@     toVegaLite [ height 300, someData [], enc [], bar [ MHeight 20 ] ]  -barAlign :: Double -> VegaLite-barAlign x =+bAlign :: [ScaleProperty] -> Double -> VegaLite+bAlign sOpts x =     let         enc =             encoding                 . position X                     [ pName "cat"                     , pOrdinal-                    , PScale [ SAlign x, SPaddingInner 0.5 ]+                    , PScale ([ SAlign x, SPaddingInner 0.5 ] ++ sOpts)                     ]                 . position Y [ pName "val", pQuant ]     in     toVegaLite [ width 400, someData [], enc [], bar [] ]  +barAlign :: Double -> VegaLite+barAlign = bAlign []+++barAlignR :: Double -> VegaLite+barAlignR = bAlign [SReverse True]++ position8, position9, position10, position11, position12 :: VegaLite position8 = barAlign (-10)  -- test clamping position9 = barAlign 0.3 position10 = barAlign 0.5 position11 = barAlign 0.7 position12 = barAlign 10    -- test clamping++position8r, position9r, position10r, position11r, position12r :: VegaLite+position8r = barAlignR (-10)  -- test clamping+position9r = barAlignR 0.3+position10r = barAlignR 0.5+position11r = barAlignR 0.7+position12r = barAlignR 10    -- test clamping
tests/ProjectionTests.hs view
@@ -87,13 +87,13 @@     let         cfg =             configure-                . configuration (Background "rgb(251,247,238)")+                . configuration (BackgroundStyle "rgb(251,247,238)")                 . configuration (TitleStyle [ TFont "Roboto", TFontWeight W600, TFontSize 18 ])-                . configuration (View [ ViewContinuousWidth 500-                                      , ViewContinuousHeight 300-                                      , ViewStroke Nothing ])-                . configuration (Autosize [ AFit ])-                . configuration (Projection [ PrType Orthographic, PrRotate 0 0 0 ])+                . configuration (ViewStyle [ ViewContinuousWidth 500+                                           , ViewContinuousHeight 300+                                           , ViewNoStroke ])+                . configuration (AutosizeStyle [ AFit ])+                . configuration (ProjectionStyle [ PrType Orthographic, PrRotate 0 0 0 ])          globeSpec =             asSpec
tests/ScaleTests.hs view
@@ -17,6 +17,8 @@             , ("scale7", scale7)             , ("scale8", scale8)             , ("scale9", scale9)+            , ("diverging1", diverging1)+            , ("diverging2", diverging2)             ]  scale1 :: VegaLite@@ -41,7 +43,7 @@     let         conf =             configure-                . configuration (Range [ RRamp "reds" ])+                . configuration (RangeStyle [ RRamp "reds" ])          cars =             dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []@@ -226,3 +228,37 @@                     ]     in     toVegaLite [ dataVals [], mark Point [], enc [] ]+++divergingData :: Data+divergingData =+  dataFromColumns []+  . dataColumn "category" (Strings ["A", "B", "C", "D", "E", "F", "G", "H", "I"])+  . dataColumn "value" (Numbers [-28.6, -1.6, -13.6, 34.4, 24.4, -3.6, -57.6, 30.4, -4.6])+  $ []++divergingEnc :: [ScaleProperty] -> PropertySpec+divergingEnc sopts =+  encoding+  . position X [ PName "category"+               , PmType Ordinal+               , PAxis [ AxLabelAngle 0, AxDomain False, AxOrient STop ]+               ]+  . position Y [ PName "value", PmType Quantitative ]+  . color [ MName "value"+          , MmType Quantitative+          , MScale ([ SScheme "redblue" [] ] ++ sopts)+          ]+  $ []++diverging1 :: VegaLite+diverging1 = toVegaLite [ divergingData+                        , divergingEnc []+                        , mark Bar []+                        ]++diverging2 :: VegaLite+diverging2 = toVegaLite [ divergingData+                        , divergingEnc [ SDomainMid 0 ]+                        , mark Bar []+                        ]
tests/ShapeTests.hs view
@@ -257,7 +257,7 @@     let         config =             configure-                . configuration (View [ ViewStroke Nothing ])+                . configuration (ViewStyle [ ViewNoStroke ])          dataVals =             dataFromColumns []
tests/Test.hs view
@@ -44,6 +44,7 @@ import qualified ConditionalTests as CondT import qualified ConfigTests as ConfT import qualified DataTests as DT+import qualified EncodingTests import qualified FillStrokeTests as FST import qualified GeoTests as GT import qualified HyperlinkTests as HT@@ -60,6 +61,7 @@ import qualified TimeTests as TmT import qualified TooltipTests as TT import qualified TrailTests as TrT+import qualified TransformTests import qualified ViewCompositionTests as VT import qualified WindowTransformTests as WT @@ -115,6 +117,7 @@   , toTests "Conditional" "conditional" CondT.testSpecs   , toTests "Config" "config" ConfT.testSpecs   , toTests "Data" "data" DT.testSpecs+  , toTests "Encoding" "encoding" EncodingTests.testSpecs   , toTests "FillStroke" "fillstroke" FST.testSpecs   , toTests "Geo" "geo" GT.testSpecs   , toTests "Hyperlink" "hyperlink" HT.testSpecs@@ -131,6 +134,7 @@   , toTests "Time" "time" TmT.testSpecs   , toTests "Tooltip" "tooltip" TT.testSpecs   , toTests "Trail" "trail" TrT.testSpecs+  , toTests "Transform" "transform" TransformTests.testSpecs   , toTests "ViewComposition" "viewcomposition" VT.testSpecs   , toTests "WindowTransform" "windowtransform" WT.testSpecs   ]
+ tests/TransformTests.hs view
@@ -0,0 +1,427 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module TransformTests (testSpecs) where++import qualified Data.Text as T++import Data.Aeson (Value)+import Data.Aeson.QQ.Simple (aesonQQ)++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif++import Prelude hiding (filter, lookup)++import Graphics.Vega.VegaLite+++testSpecs :: [(String, VegaLite)]+testSpecs = [ ("checkordering", checkOrdering)+            , ("binempty", binEmpty)+            , ("binstep", binStep)+            , ("imputemean", imputeMean)+            , ("densityplot", densityPlot)+            , ("loessplot", loessPlot)+            , ("lookupplot", lookupPlot)+            , ("pivotplot", pivotPlot)+            , ("quantileplot", quantilePlot)+            , ("regressionplot", regressionPlot)+            , ("flattenplot", flattenPlot)+            , ("foldasplot", foldAsPlot)+            , ("stackplot", stackPlot)+            , ("weatherbymonth", weatherByMonth)+            , ("weatherbytwomonths", weatherByTwoMonths)+            , ("distances", distances)+            , ("weathermaxbins", weatherMaxBins)+            , ("windowplot", windowPlot)+            , ("joinaggregateplot", joinAggregatePlot)+            ]+            ++cars :: Data+cars = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []++movies :: [Format] -> Data+movies = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json"++us :: T.Text -> Data+us feature =  dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json"+              [ TopojsonFeature feature ]+++pos :: Position -> FieldName -> Measurement -> BuildEncodingSpecs+pos ax n t = position ax [ PName n, PmType t ]++checkOrdering :: VegaLite+checkOrdering =+  let trans = transform+              -- calculateAs transform first to test that order of transforms is preserved.+              . calculateAs "datum.Acceleration" "myAcceleration"+              . aggregate [ opAs Mean "myAcceleration" "mean_acceleration" ]+                          [ "Cylinders" ]++      enc = encoding+            . pos X "Cylinders" Ordinal+            . pos Y "mean_acceleration" Quantitative++  in toVegaLite [ cars, trans [], enc [], mark Bar [] ]+++binTransform :: [BinProperty] -> VegaLite+binTransform bProps =+  let trans = transform+              . calculateAs "datum.IMDB_Rating" "rating"+              . filter (FExpr "datum.rating != null")+              . binAs bProps "rating" "ratingGroup"++      enc = encoding+            . pos X "ratingGroup" Ordinal+            . position Y [ PAggregate Count+                         , PmType Quantitative+                         , PTitle "Number of movies" ]++  in toVegaLite [ width 400, movies [], trans [], enc [], mark Bar [] ]++binEmpty :: VegaLite+binEmpty = binTransform []++binStep :: VegaLite+binStep = binTransform [ Step 0.25 ]++imputeMean :: VegaLite+imputeMean =+  let imputeData =+        dataFromColumns []+        . dataColumn "A" (Numbers [ 0, 0, 1, 1, 2, 2, 3 ])+        . dataColumn "B" (Numbers [ 28, 91, 43, 55, 81, 53, 19 ])+        . dataColumn "C" (Numbers [ 0, 1, 0, 1, 0, 1, 0 ])++      trans =+        transform+        . calculateAs "datum.A" "a"+        . calculateAs "datum.B" "b"+        . calculateAs "datum.C" "c"+        . impute "b" "a" [ ImMethod ImMean+                         , ImGroupBy [ "c" ]+                         , ImFrame (Just (-2)) (Just 2)+                         ]++      enc =+        encoding+        . pos X "a" Quantitative+        . pos Y "b" Quantitative+        . color [ MName "c", MmType Nominal ]++      lopts = [ MStrokeDash [ 5, 10, 5 ]+              , MStrokeOpacity 0.5+              , MStrokeWidth 2+              ]++  in toVegaLite [ imputeData [], trans [], enc [], mark Line lopts ]+++densityPlot :: VegaLite+densityPlot =+  let trans = transform+              . filter (FExpr "datum.IMDB_Rating != null")+              . density "IMDB_Rating" [ DnBandwidth 0.3 ]++      enc = encoding+            . position X [ PName "value", PmType Quantitative, PTitle "IMDB Rating" ]+            . pos Y "density" Quantitative++      aopts = [ MFillOpacity 0.8+              , MFill "teal"+              , MStroke "firebrick"+              , MStrokeWidth 2+              , MStrokeOpacity 0.7 ]+      +  in toVegaLite [ width 400, height 400, movies [], trans [], enc [], mark Area aopts ]+++loessPlot :: VegaLite+loessPlot =+  let trans = transform+              . calculateAs "datum.IMDB_Rating" "imdbRating"+              . calculateAs "datum.Rotten_Tomatoes_Rating" "rtRating"+              . loess "imdbRating" "rtRating" [ LsBandwidth 0.1+                                              , LsAs "tx" "ty" ]++      enc1 = encoding+             . pos X "Rotten_Tomatoes_Rating" Quantitative+             . pos Y "IMDB_Rating" Quantitative++      enc2 = encoding+             . pos X "tx" Quantitative+             . pos Y "ty" Quantitative++      pointSpec = asSpec [ enc1 [], mark Point [ MFilled True, MOpacity 0.3 ] ]+      trendSpec = asSpec [ trans [], enc2 [], mark Line [ MColor "orange" ] ]+      +  in toVegaLite [ width 300, height 300, movies [], layer [ pointSpec, trendSpec ] ]+++lookupPlot :: VegaLite+lookupPlot =+  let unemployed = dataFromUrl "https://vega.github.io/vega-lite/data/unemployment.tsv" []++      trans = transform+              . calculateAs "datum.id" "countyID"+              . lookup "countyID" unemployed "id" (LuFields [ "rate" ])++      proj = projection [ PrType AlbersUsa ]++      enc = encoding+            . color [ MName "rate"+                    , MmType Quantitative+                    , MScale [ SType ScQuantize, SScheme "category10" [ 10 ] ]+                    ]++  in toVegaLite [ width 500, height 300, us "counties", proj, trans [], enc [],+                  mark Geoshape [] ]+++pivotPlot :: VegaLite+pivotPlot =+  let temps = dataFromColumns []+              . dataColumn "city" (Strings [ "Bristol", "Bristol", "Sheffield", "Sheffield", "Glasgow", "Glasgow" ])+              . dataColumn "temp" (Numbers [ 12, 14, 11, 13, 7, 10 ])+              . dataColumn "year" (Numbers [ 2017, 2018, 2017, 2018, 2017, 2018 ])++      trans =+        transform+        . calculateAs "datum.year" "Year"+        . calculateAs "datum.city" "City"+        . calculateAs "datum.temp" "Temperature"+        . pivot "Year" "Temperature" [ PiGroupBy [ "City" ] ]++      -- 2017 temperatures for the Bristol, Sheffield and Glasgow+      enc =+        encoding+        . pos X "2017" Quantitative+        . pos Y "City" Nominal++  in toVegaLite [ temps [], trans [], enc [], mark Circle [] ]+++quantilePlot :: VegaLite+quantilePlot =+  let norm = dataFromUrl "https://vega.github.io/vega-lite/data/normal-2d.json" []++      trans =+        transform+        . quantile "u" [ QtStep 0.01, QtAs "p" "v" ]+        . calculateAs "quantileUniform(datum.p)" "unif"+        . calculateAs "quantileNormal(datum.p)" "norm"++      enc1 = encoding . pos X "unif" Quantitative . pos Y "v" Quantitative+      enc2 = encoding . pos X "norm" Quantitative . pos Y "v" Quantitative++  in toVegaLite [ norm+                , trans []+                , hConcat [ asSpec [ enc1 [], mark Point [] ]+                          , asSpec [ enc2 [], mark Point [] ]+                          ]+                ]++regressionPlot :: VegaLite+regressionPlot =+  let trans =+        transform+        . calculateAs "datum.IMDB_Rating" "imdbRating"+        . calculateAs "datum.Rotten_Tomatoes_Rating" "rtRating"+        . regression "imdbRating" "rtRating" [ RgMethod RgPoly+                                             , RgOrder 3+                                             , RgExtent 10 90 ]++      enc1 = encoding+             . pos X "Rotten_Tomatoes_Rating" Quantitative+             . pos Y "IMDB_Rating" Quantitative++      enc2 = encoding+             . pos X "rtRating" Quantitative+             . pos Y "imdbRating" Quantitative++      pointSpec = asSpec [ enc1 [], mark Point [ MFilled True, MOpacity 0.3 ] ]+      regSpec = asSpec [ trans [], enc2 [], mark Line [ MColor "firebrick" ] ]++  in toVegaLite [ width 300, height 300, movies [], layer [ pointSpec, regSpec ] ]+++dummyData :: Value+dummyData = [aesonQQ|+[ { "key": "alpha", "foo": [ 1, 2 ], "bar": [ "A", "B" ] }+, { "key": "beta", "foo": [ 3, 4, 5 ], "bar": [ "C", "D" ] }+]+|]++flattenPlot :: VegaLite+flattenPlot =+  let dvals = dataFromJson dummyData []++      trans = transform . flattenAs [ "foo", "bar" ] [ "quant", "cat" ]++      enc = encoding+            . pos X "quant" Quantitative+            . pos Y "cat" Nominal+            . color [ MName "key", MmType Nominal ]++  in toVegaLite [ dvals, trans [], mark Circle [], enc [] ]+++foldAsPlot :: VegaLite+foldAsPlot =+  let dvals = dataFromColumns []+              . dataColumn "country" (Strings [ "USA", "Canada" ])+              . dataColumn "gold" (Numbers [ 10, 7 ])+              . dataColumn "silver" (Numbers [ 20, 26 ])++      trans = transform+              . calculateAs "datum.gold" "goldMedals"+              . calculateAs "datum.silver" "silverMedals"+              . foldAs [ "goldMedals", "silverMedals" ] "k" "v"+              . calculateAs "datum.k" "year"+              . calculateAs "datum.v" "numberOfMedals"++      enc = encoding+            . column [ FName "year", FmType Nominal ]+            . pos X "country" Nominal+            . pos Y "numberOfMedals" Quantitative+            . color [ MName "country", MmType Nominal, MLegend [] ]++  in toVegaLite [ dvals [], trans [], mark Bar [], enc [] ]+++stackPlot :: VegaLite+stackPlot =+  let trans = transform+              . aggregate [ opAs Count "" "count_*" ] [ "Origin", "Cylinders" ]+              . stack "count_*"+                       []+                       "stack_count_Origin1"+                       "stack_count_Origin2"+                       [ StOffset StNormalize, StSort [ WAscending "Origin" ] ]+              . window+                    [ ( [ WAggregateOp Min, WField "stack_count_Origin1" ], "x" )+                    , ( [ WAggregateOp Max, WField "stack_count_Origin2" ], "x2" )+                    ]+                    [ WFrame Nothing Nothing, WGroupBy [ "Origin" ] ]+              . stack "count_*"+                    [ "Origin" ]+                    "y"+                    "y2"+                    [ StOffset StNormalize, StSort [ WAscending "Cylinders" ] ]++      enc = encoding+            . position X [ PName "x", PmType Quantitative, PAxis [] ]+            . position X2 [ PName "x2" ]+            . position Y [ PName "y", PmType Quantitative, PAxis [] ]+            . position Y2 [ PName "y2" ]+            . color [ MName "Origin", MmType Nominal ]+            . opacity [ MName "Cylinders", MmType Quantitative, MLegend [] ]+            . tooltips+                    [ [ TName "Origin", TmType Nominal ]+                    , [ TName "Cylinders", TmType Quantitative ]+                    ]+++  in toVegaLite [ cars, trans [], enc [], mark Rect [] ]+++weather :: TimeUnit -> FieldName -> VegaLite+weather tunit field =+  let weatherData = dataFromUrl "https://vega.github.io/vega-lite/data/seattle-weather.csv"+                    [ Parse [ ( "date", FoDate "%Y/%m/%d" ) ] ]++      trans = transform+              . calculateAs "datum.date" "sampleDate"+              . calculateAs "datum.temp_max" "maxTemp"+              . timeUnitAs tunit "sampleDate" field++      enc = encoding+            . position X [ PName field, PmType Temporal, PAxis [ AxFormat "%b" ] ]+            . position Y [ PName "maxTemp", PmType Quantitative, PAggregate Max ]++  in toVegaLite [ width 400+                , weatherData+                , trans []+                , enc []+                , mark Line [ MPoint (PMMarker [ MFill "black" ]) ]+                ]++weatherByMonth :: VegaLite+weatherByMonth = weather Month "month"++weatherByTwoMonths :: VegaLite+weatherByTwoMonths = weather (TUStep 2 Month) "bimonth"++weatherMaxBins :: VegaLite+weatherMaxBins = weather (TUMaxBins 3) "tbin"+++distances :: VegaLite+distances =+  let dateTime mnt = "Sun, 01 Jan 2012 00:0" <> T.pack (show mnt) <> ":00"+      dates = map dateTime [1 :: Int .. 15]++      dvals = dataFromColumns []+              . dataColumn "date" (Strings dates)+              . dataColumn "distance" (Numbers [ 1, 1, 2, 1, 4, 2, 5, 2, 6, 4, 1, 1, 3, 0, 2, 3 ])++      enc = encoding+            . position X [ PName "date"+                         , PmType Temporal+                         , PTimeUnit (TUMaxBins 15) ]+            . position Y [ PName "distance"+                         , PmType Quantitative+                         , PAggregate Sum ]++  in toVegaLite [ dvals [], enc [], mark Bar [] ]+++activityData :: Data+activityData =+  dataFromColumns []+  . dataColumn "Activity" (Strings [ "Sleeping", "Eating", "TV", "Work", "Exercise" ])+  . dataColumn "Time" (Numbers [ 8, 2, 4, 8, 2 ])+  $ []++windowPlot :: VegaLite+windowPlot =+  let trans = transform+              . window [ ( [ WAggregateOp Sum, WField "Time" ], "TotalTime" ) ]+                       [ WFrame Nothing Nothing ]+              . calculateAs "datum.Time/datum.TotalTime * 100" "PercentOfTotal"++      enc = encoding+            . position X [ PName "PercentOfTotal", PmType Quantitative, PTitle "% of total time" ]+            . pos Y "Activity" Nominal++  in toVegaLite+        [ heightStep 12+        , activityData+        , trans []+        , mark Bar []+        , enc []+        ]++joinAggregatePlot :: VegaLite+joinAggregatePlot =+  let trans = transform+              . joinAggregate [ opAs Sum "Time" "TotalTime" ] []+              . calculateAs "datum.Time/datum.TotalTime * 100" "PercentOfTotal"++      enc = encoding+            . position X [ PName "PercentOfTotal", PmType Quantitative, PTitle "% of total time" ]+            . pos Y "Activity" Nominal++  in toVegaLite+        [ heightStep 12+        , activityData+        , trans []+        , mark Bar []+        , enc []+        ]
tests/ViewCompositionTests.hs view
@@ -5,6 +5,7 @@ -- module ViewCompositionTests (testSpecs) where +import qualified Data.Text as T import qualified Prelude as P  import Graphics.Vega.VegaLite@@ -17,6 +18,7 @@             , ("columns2", columns2)             , ("columns3", columns3)             , ("columns4", columns4)+            , ("groupyage", groupByAge)             , ("grid1", grid1)             , ("grid2", grid2)             , ("grid3", grid3)@@ -25,6 +27,11 @@             ]  +noStroke :: [ConfigureSpec] -> PropertySpec+noStroke = configure+           . configuration (ViewStyle [ ViewNoStroke ])++ genderChart :: [HeaderProperty] -> [HeaderProperty] -> VegaLite genderChart hdProps cProps =   let conf = configure . configuration (HeaderStyle cProps)@@ -43,6 +50,7 @@                   [ FName "gender"                   , FmType Nominal                   , FHeader hdProps+                  , FSpacing 0                   ]               . position X                   [ PName "age"@@ -76,6 +84,52 @@         ]         [] ++groupByAge :: VegaLite+groupByAge =+  let conf = noStroke+             . configuration (Axis [ DomainWidth 1 ] )++      pop = dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []++      trans =+          transform+              . filter (FExpr "datum.year == 2000")+              . calculateAs "datum.sex == 2 ? 'Female' : 'Male'" "gender"++      enc =+          encoding+              . column+                  [ FName "age"+                  , FmType Ordinal+                  , FSpacing 10+                  ]+              . position Y+                  [ PName "people"+                  , PmType Quantitative+                  , PAggregate Sum+                  , PAxis [ AxTitle "Population", AxGrid False ]+                  ]+              . position X+                  [ PName "gender"+                  , PmType Nominal+                  , PAxis [ AxNoTitle ]+                  ]+              . color+                  [ MName "gender"+                  , MmType Nominal+                  , MScale [ SRange (RStrings [ "#675193", "#ca8861" ]) ]+                  ]++  in toVegaLite [ conf []+                , pop+                , trans []+                , widthStep 12+                , mark Bar []+                , enc []+                ]++ dataVals :: [DataColumn] -> Data dataVals =     let@@ -115,23 +169,27 @@ gridTransform = transform                 (calculateAs "datum.row * 1000 + datum.col" "index" []) -gridConfig :: [FacetConfig] -> [ConfigureSpec] -> PropertySpec+gridConfig :: [CompositionConfig] -> [ConfigureSpec] -> PropertySpec gridConfig fopts =   configure   . configuration (HeaderStyle [ HLabelFontSize 0.1 ])-  . configuration (View [ ViewStroke Nothing, ViewContinuousHeight 120 ])+  . configuration (ViewStyle [ ViewStroke "black"+                             , ViewStrokeWidth 2+                             , ViewFill "gray"+                             , ViewFillOpacity 0.2+                             , ViewContinuousHeight 120 ])   . configuration (FacetStyle fopts)   grid1 :: VegaLite grid1 =-    let cfg = gridConfig [ FSpacing 80, FColumns 5 ]+    let cfg = gridConfig [ CompSpacing 80, CompColumns 5 ]      in     toVegaLite         [ cfg []         , dataVals []-        , spacingRC 20 80+        , spacingRC 10 30         , specification specByCatVal         , facet             [ RowBy [ FName "row", FmType Ordinal, FNoTitle ]@@ -142,7 +200,7 @@  grid2 :: VegaLite grid2 =-    let cfg = gridConfig [ FSpacing 80, FColumns 5 ]+    let cfg = gridConfig [ CompSpacing 80, CompColumns 5 ]      in     toVegaLite@@ -155,20 +213,16 @@         ]  --- This has been changed from the Elm version so that it validates--- against the v3.4.0 specification.--- (not sure if this is still a valid comment)--- grid3 :: VegaLite grid3 =-    let cfg = gridConfig [ FSpacing 80 ]+    let cfg = gridConfig [ CompSpacing 80 ]      in     toVegaLite         [ cfg []         , dataVals []         , gridTransform-        , columns 5+        , columns 0         , specification specByCatVal         , facetFlow [ FName "index", FmType Ordinal, FHeader [ HNoTitle ] ]         ]@@ -188,10 +242,14 @@   in toVegaLite (specification spec : opts)  +carFields :: [T.Text]+carFields = [ "Horsepower", "Miles_per_Gallon", "Acceleration", "Displacement", "Weight_in_lbs" ]++ grid4 :: VegaLite grid4 =   let opts = [ columns 3-             , repeatFlow [ "Horsepower", "Miles_per_Gallon", "Acceleration", "Displacement", "Weight_in_lbs" ]+             , repeatFlow carFields              ]    in carGrid Flow opts@@ -200,7 +258,7 @@ grid5 :: VegaLite grid5 =   let opts = [ repeat-               [ RowFields [ "Horsepower", "Miles_per_Gallon", "Acceleration", "Displacement", "Weight_in_lbs" ]+               [ RowFields carFields                ]              ] 
tests/WindowTransformTests.hs view
@@ -73,13 +73,13 @@     toVegaLite [ dataVals [], trans [], layer [ barSpec, ruleSpec ] ]  +movieData :: Data+movieData = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json"+                [ Parse [ ( "Release_Date", FoDate "%b %d %Y" ) ] ]+ window3 :: VegaLite window3 =-    let dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/movies.json"-                [ Parse [ ( "Release_Date", FoDate "%d-%b-%y" ) ] ]--        trans =+    let trans =             transform                 . filter (FExpr "datum.IMDB_Rating != null")                 . timeUnitAs Year "Release_Date" "year"@@ -103,16 +103,12 @@          tickSpec = asSpec [ mark Tick [], tickEnc [] ]             -    in toVegaLite [ dataVals, trans [], layer [ barSpec, tickSpec ] ]+    in toVegaLite [ movieData, trans [], layer [ barSpec, tickSpec ] ]   window4 :: VegaLite window4 =-    let dataVals =-            dataFromUrl "https://vega.github.io/vega-lite/data/movies.json"-                [ Parse [ ( "Release_Date", FoDate "%d-%b-%y" ) ] ]--        trans =+    let trans =             transform                 . filter (FExpr "datum.IMDB_Rating != null")                 . filter (FRange "Release_Date" (DateRange [] [ DTYear 2019 ]))@@ -125,7 +121,7 @@                 . position X [ PName "Release_Date", PmType Temporal ]                 . position Y [ PName "RatingDelta", PmType Quantitative, PAxis [ AxTitle "Residual" ] ]                 -    in toVegaLite [ dataVals, trans [], enc [], mark Point [ MStrokeWidth 0.3, MOpacity 0.3 ] ]+    in toVegaLite [ movieData, trans [], enc [], mark Point [ MStrokeWidth 0.3, MOpacity 0.3 ] ]   window5 :: VegaLite
+ tests/specs/axis/axis1c.vl view
@@ -0,0 +1,549 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis2c.vl view
@@ -0,0 +1,549 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "catX",+            "type": "ordinal"+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis3c.vl view
@@ -0,0 +1,549 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "date",+            "type": "temporal"+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis4c.vl view
@@ -0,0 +1,557 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "values": [+                    1,+                    25,+                    39,+                    90+                ]+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis5c.vl view
@@ -0,0 +1,558 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "catX",+            "type": "ordinal",+            "axis": {+                "values": [+                    "1",+                    "25",+                    "39",+                    "dummy",+                    "90"+                ]+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis6c.vl view
@@ -0,0 +1,116 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "date": "2019-01-01 09:00:00",+                "y": 1+            },+            {+                "date": "2019-01-02 09:00:00",+                "y": 2+            },+            {+                "date": "2019-01-03 09:00:00",+                "y": 3+            },+            {+                "date": "2019-01-04 09:00:00",+                "y": 4+            },+            {+                "date": "2019-01-05 09:00:00",+                "y": 5+            },+            {+                "date": "2019-01-06 09:00:00",+                "y": 6+            },+            {+                "date": "2019-01-07 09:00:00",+                "y": 7+            },+            {+                "date": "2019-01-08 09:00:00",+                "y": 8+            },+            {+                "date": "2019-01-09 09:00:00",+                "y": 9+            },+            {+                "date": "2019-01-10 09:00:00",+                "y": 10+            },+            {+                "date": "2019-01-11 09:00:00",+                "y": 11+            },+            {+                "date": "2019-01-12 09:00:00",+                "y": 12+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "date",+            "type": "temporal",+            "axis": {+                "values": [+                    {+                        "date": 4,+                        "year": 2019,+                        "month": "Jan"+                    },+                    {+                        "date": 8,+                        "year": 2019,+                        "month": "Jan"+                    },+                    {+                        "date": 20,+                        "year": 2019,+                        "month": "Jan"+                    }+                ]+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis7c.vl view
@@ -0,0 +1,552 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "labelExpr": "datum.value / 100"+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis8c.vl view
@@ -0,0 +1,552 @@+{+    "config": {+        "axisTemporal": {+            "domainColor": "brown",+            "labelColor": "purple",+            "grid": false,+            "domainDash": [+                4,+                2+            ]+        },+        "axisQuantitative": {+            "domainColor": "orange",+            "tickOffset": 10,+            "labelOffset": 10,+            "gridColor": "seagreen",+            "labelFont": "Comic Sans MS"+        },+        "line": {+            "strokeWidth": 2,+            "stroke": "gray"+        },+        "point": {+            "strokeWidth": 1,+            "stroke": "black",+            "fill": "yellow",+            "strokeOpacity": 0.4+        }+    },+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "catX",+            "type": "ordinal",+            "axis": {+                "labelExpr": "'number' + datum.label"+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axisstyleempty.vl view
@@ -0,0 +1,25 @@+{+    "config": {+        "style": {}+    },+    "mark": "point",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "Origin",+            "type": "nominal",+            "legend": null+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axisstyleemptyx.vl view
@@ -0,0 +1,30 @@+{+    "config": {+        "style": {+            "x-style": {}+        }+    },+    "mark": "point",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "Origin",+            "type": "nominal",+            "legend": null+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative",+            "axis": {+                "style": "x-style"+            }+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axisstylex.vl view
@@ -0,0 +1,34 @@+{+    "config": {+        "style": {+            "x-style": {+                "domainColor": "orange",+                "labelExpr": "if (datum.value <= 100, 'low:' + datum.label, 'high:' + datum.label)",+                "gridColor": "lightgreen"+            }+        }+    },+    "mark": "point",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "Origin",+            "type": "nominal",+            "legend": null+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative",+            "axis": {+                "style": "x-style"+            }+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axisstylexy.vl view
@@ -0,0 +1,44 @@+{+    "config": {+        "style": {+            "x-style": {+                "domainColor": "orange",+                "labelExpr": "if (datum.value <= 100, 'low:' + datum.label, 'high:' + datum.label)",+                "gridColor": "lightgreen"+            },+            "y-style": {+                "domain": false,+                "labels": false,+                "grid": false,+                "title": null,+                "ticks": false+            }+        }+    },+    "mark": "point",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "Origin",+            "type": "nominal",+            "legend": null+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative",+            "axis": {+                "style": "x-style"+            }+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative",+            "axis": {+                "style": "y-style"+            }+        }+    }+}
+ tests/specs/composite/boxplotnobox.vl view
@@ -0,0 +1,29 @@+{+    "config": {+        "boxplot": {+            "ticks": true+        }+    },+    "mark": {+        "box": false,+        "extent": 0.5,+        "type": "boxplot"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "age",+            "type": "ordinal"+        },+        "y": {+            "field": "people",+            "type": "quantitative",+            "axis": {+                "title": "Population"+            }+        }+    }+}
+ tests/specs/composite/boxplotnomedian.vl view
@@ -0,0 +1,29 @@+{+    "config": {+        "boxplot": {+            "ticks": true+        }+    },+    "mark": {+        "median": false,+        "extent": 0.5,+        "type": "boxplot"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "age",+            "type": "ordinal"+        },+        "y": {+            "field": "people",+            "type": "quantitative",+            "axis": {+                "title": "Population"+            }+        }+    }+}
+ tests/specs/composite/boxplotnooutliers.vl view
@@ -0,0 +1,29 @@+{+    "config": {+        "boxplot": {+            "ticks": true+        }+    },+    "mark": {+        "extent": 0.5,+        "outliers": false,+        "type": "boxplot"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "age",+            "type": "ordinal"+        },+        "y": {+            "field": "people",+            "type": "quantitative",+            "axis": {+                "title": "Population"+            }+        }+    }+}
+ tests/specs/composite/boxplotnorule.vl view
@@ -0,0 +1,29 @@+{+    "config": {+        "boxplot": {+            "ticks": true+        }+    },+    "mark": {+        "rule": false,+        "extent": 0.5,+        "type": "boxplot"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "age",+            "type": "ordinal"+        },+        "y": {+            "field": "people",+            "type": "quantitative",+            "axis": {+                "title": "Population"+            }+        }+    }+}
+ tests/specs/composite/boxplotnoticks.vl view
@@ -0,0 +1,29 @@+{+    "config": {+        "boxplot": {+            "ticks": true+        }+    },+    "mark": {+        "extent": 0.5,+        "type": "boxplot",+        "ticks": false+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "age",+            "type": "ordinal"+        },+        "y": {+            "field": "people",+            "type": "quantitative",+            "axis": {+                "title": "Population"+            }+        }+    }+}
tests/specs/composite/errorband1.vl view
@@ -1,6 +1,6 @@ {     "mark": {-        "borders": {},+        "borders": true,         "extent": "ci",         "interpolate": "monotone",         "type": "errorband"
+ tests/specs/composite/errorband1no.vl view
@@ -0,0 +1,27 @@+{+    "mark": {+        "borders": false,+        "extent": "ci",+        "interpolate": "monotone",+        "type": "errorband"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "Year",+            "timeUnit": "year",+            "type": "temporal"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "scale": {+                "zero": false+            },+            "title": "Miles per Gallon (95% CI)",+            "type": "quantitative"+        }+    }+}
tests/specs/composite/errorband2.vl view
@@ -1,6 +1,6 @@ {     "mark": {-        "borders": {},+        "borders": true,         "extent": "stdev",         "interpolate": "monotone",         "type": "errorband"
+ tests/specs/composite/errorband2no.vl view
@@ -0,0 +1,27 @@+{+    "mark": {+        "borders": false,+        "extent": "stdev",+        "interpolate": "monotone",+        "type": "errorband"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "Year",+            "timeUnit": "year",+            "type": "temporal"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "scale": {+                "zero": false+            },+            "title": "Miles per Gallon (1 stdev)",+            "type": "quantitative"+        }+    }+}
tests/specs/composite/errorbar3.vl view
@@ -7,7 +7,7 @@         {             "mark": {                 "type": "errorbar",-                "ticks": {}+                "ticks": true             },             "encoding": {                 "color": {
+ tests/specs/composite/errorbar3no.vl view
@@ -0,0 +1,49 @@+{+    "data": {+        "url": "https://vega.github.io/vega-lite/data/barley.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "type": "errorbar",+                "ticks": false+            },+            "encoding": {+                "color": {+                    "value": "#4682b4"+                },+                "x": {+                    "field": "yield",+                    "scale": {+                        "zero": false+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "variety",+                    "type": "ordinal"+                }+            }+        },+        {+            "mark": {+                "color": "black",+                "type": "point",+                "filled": true+            },+            "encoding": {+                "x": {+                    "field": "yield",+                    "aggregate": "mean",+                    "type": "quantitative"+                },+                "y": {+                    "field": "variety",+                    "type": "ordinal"+                }+            }+        }+    ],+    "description": "Error bars with color encoding"+}
tests/specs/composite/errorbar4.vl view
@@ -32,7 +32,7 @@         {             "mark": {                 "type": "errorbar",-                "ticks": {}+                "ticks": true             },             "encoding": {                 "x": {
tests/specs/composite/errorbar5.vl view
@@ -32,7 +32,7 @@         {             "mark": {                 "type": "errorbar",-                "ticks": {}+                "ticks": true             },             "encoding": {                 "xError2": {
tests/specs/composite/errorbar6.vl view
@@ -32,7 +32,7 @@         {             "mark": {                 "type": "errorbar",-                "ticks": {}+                "ticks": true             },             "encoding": {                 "yError": {
tests/specs/composite/errorbar7.vl view
@@ -32,7 +32,7 @@         {             "mark": {                 "type": "errorbar",-                "ticks": {}+                "ticks": true             },             "encoding": {                 "yError2": {
tests/specs/conditional/axisCondition2.vl view
@@ -14,6 +14,13 @@             "field": "IMDB_Rating",             "type": "quantitative",             "axis": {+                "tickSize": {+                    "value": 5,+                    "condition": {+                        "value": 20,+                        "test": "(datum.value > 0) && (datum.value < 3)"+                    }+                },                 "tickWidth": {                     "value": 2,                     "condition": {@@ -37,6 +44,13 @@                     "condition": {                         "value": 0.3,                         "test": "datum.value >=8"+                    }+                },+                "labelPadding": {+                    "value": 5,+                    "condition": {+                        "value": 20,+                        "test": "(datum.value >= 1) && (datum.value <= 4)"                     }                 },                 "tickColor": {
tests/specs/conditional/axisDateCondition1.vl view
@@ -1,6 +1,6 @@ {     "mark": {-        "borders": {},+        "borders": true,         "extent": "iqr",         "interpolate": "monotone",         "type": "errorband"
+ tests/specs/conditional/axisconditionlabeloffset.vl view
@@ -0,0 +1,32 @@+{+    "height": 600,+    "mark": {+        "opacity": 0.1,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "width": 600,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "IMDB_Rating",+            "type": "quantitative",+            "axis": {+                "labelOffset": {+                    "value": 5,+                    "condition": {+                        "value": 10,+                        "test": "datum.value <= 5"+                    }+                },+                "tickCount": 20+            }+        },+        "y": {+            "field": "Rotten_Tomatoes_Rating",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/fontCfg.vl view
@@ -0,0 +1,34 @@+{+    "height": 200,+    "config": {+        "font": "Comic Sans MS"+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/data/domain1.vl view
@@ -0,0 +1,40 @@+{+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "y": 95+            },+            {+                "x": 2,+                "y": 97+            },+            {+                "x": 3,+                "y": 100+            },+            {+                "x": 4,+                "y": 105+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "scale": {+                "zero": false+            },+            "type": "quantitative"+        }+    }+}
+ tests/specs/data/domain2.vl view
@@ -0,0 +1,44 @@+{+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "y": 95+            },+            {+                "x": 2,+                "y": 97+            },+            {+                "x": 3,+                "y": 100+            },+            {+                "x": 4,+                "y": 105+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "scale": {+                "domain": [+                    90,+                    100+                ],+                "zero": false+            },+            "type": "quantitative"+        }+    }+}
+ tests/specs/data/domain3.vl view
@@ -0,0 +1,46 @@+{+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "y": 95+            },+            {+                "x": 2,+                "y": 97+            },+            {+                "x": 3,+                "y": 100+            },+            {+                "x": 4,+                "y": 105+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "scale": {+                "domain": {+                    "unionWith": [+                        90,+                        100+                    ]+                },+                "zero": false+            },+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/hrounded.vl view
@@ -0,0 +1,57 @@+{+    "mark": {+        "cornerRadiusEnd": 4,+        "type": "bar"+    },+    "data": {+        "values": [+            {+                "a": "A",+                "b": 28+            },+            {+                "a": "B",+                "b": 55+            },+            {+                "a": "C",+                "b": 43+            },+            {+                "a": "D",+                "b": 91+            },+            {+                "a": "E",+                "b": 81+            },+            {+                "a": "F",+                "b": 53+            },+            {+                "a": "G",+                "b": 19+            },+            {+                "a": "H",+                "b": 87+            },+            {+                "a": "I",+                "b": 52+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "b",+            "type": "quantitative"+        },+        "y": {+            "field": "a",+            "type": "ordinal"+        }+    }+}
+ tests/specs/fillstroke/strokedash1.vl view
@@ -0,0 +1,26 @@+{+    "mark": {+        "strokeWidth": 1,+        "opacity": 0.6,+        "type": "line"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/stocks.csv"+    },+    "width": 350,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "strokeDash": {+            "field": "symbol",+            "type": "nominal"+        },+        "x": {+            "field": "date",+            "type": "temporal"+        },+        "y": {+            "field": "price",+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/strokedash2.vl view
@@ -0,0 +1,57 @@+{+    "mark": {+        "strokeWidth": 1,+        "opacity": 0.6,+        "type": "line"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/stocks.csv"+    },+    "width": 350,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "strokeDash": {+            "field": "symbol",+            "scale": {+                "domain": [+                    "AAPL",+                    "AMZN",+                    "GOOG",+                    "IBM",+                    "MSFT"+                ],+                "range": [+                    [+                        1,+                        0+                    ],+                    [+                        3,+                        1+                    ],+                    [+                        2,+                        3+                    ],+                    [+                        4,+                        4+                    ],+                    [+                        5,+                        6+                    ]+                ]+            },+            "type": "nominal"+        },+        "x": {+            "field": "date",+            "type": "temporal"+        },+        "y": {+            "field": "price",+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/strokedash3.vl view
@@ -0,0 +1,163 @@+{+    "config": {+        "line": {+            "strokeWidth": 1,+            "color": "orange",+            "opacity": 0.6+        },+        "axis": {+            "grid": false,+            "title": null+        }+    },+    "data": {+        "values": [+            {+                "cat": 1,+                "x": 0,+                "y": 100+            },+            {+                "cat": 1,+                "x": 1,+                "y": 100+            },+            {+                "cat": 2,+                "x": 0,+                "y": 90+            },+            {+                "cat": 2,+                "x": 1,+                "y": 90+            },+            {+                "cat": 3,+                "x": 0,+                "y": 80+            },+            {+                "cat": 3,+                "x": 1,+                "y": 80+            },+            {+                "cat": 4,+                "x": 0,+                "y": 70+            },+            {+                "cat": 4,+                "x": 1,+                "y": 70+            },+            {+                "cat": 5,+                "x": 0,+                "y": 60+            },+            {+                "cat": 5,+                "x": 1,+                "y": 60+            },+            {+                "cat": 6,+                "x": 0,+                "y": 50+            },+            {+                "cat": 6,+                "x": 1,+                "y": 50+            },+            {+                "cat": 7,+                "x": 0,+                "y": 40+            },+            {+                "cat": 7,+                "x": 1,+                "y": 40+            },+            {+                "cat": 8,+                "x": 0,+                "y": 30+            },+            {+                "cat": 8,+                "x": 1,+                "y": 30+            },+            {+                "cat": 9,+                "x": 0,+                "y": 20+            },+            {+                "cat": 9,+                "x": 1,+                "y": 20+            },+            {+                "cat": 10,+                "x": 0,+                "y": 10+            },+            {+                "cat": 10,+                "x": 1,+                "y": 10+            }+        ]+    },+    "resolve": {+        "scale": {+            "strokeDash": "independent"+        }+    },+    "concat": [+        {+            "mark": "line",+            "width": 200,+            "title": "Nominal",+            "encoding": {+                "strokeDash": {+                    "field": "cat",+                    "type": "nominal"+                },+                "x": {+                    "field": "x",+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": "line",+            "width": 200,+            "title": "Ordinal",+            "encoding": {+                "strokeDash": {+                    "field": "cat",+                    "type": "ordinal"+                },+                "x": {+                    "field": "x",+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "type": "quantitative"+                }+            }+        }+    ],+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json"+}
+ tests/specs/fillstroke/strokedash4.vl view
@@ -0,0 +1,279 @@+{+    "config": {+        "line": {+            "strokeWidth": 1,+            "color": "orange",+            "opacity": 0.6+        },+        "axis": {+            "grid": false,+            "title": null+        }+    },+    "data": {+        "values": [+            {+                "cat": 1,+                "x": 0,+                "y": 100+            },+            {+                "cat": 1,+                "x": 1,+                "y": 100+            },+            {+                "cat": 2,+                "x": 0,+                "y": 90+            },+            {+                "cat": 2,+                "x": 1,+                "y": 90+            },+            {+                "cat": 3,+                "x": 0,+                "y": 80+            },+            {+                "cat": 3,+                "x": 1,+                "y": 80+            },+            {+                "cat": 4,+                "x": 0,+                "y": 70+            },+            {+                "cat": 4,+                "x": 1,+                "y": 70+            },+            {+                "cat": 5,+                "x": 0,+                "y": 60+            },+            {+                "cat": 5,+                "x": 1,+                "y": 60+            },+            {+                "cat": 6,+                "x": 0,+                "y": 50+            },+            {+                "cat": 6,+                "x": 1,+                "y": 50+            },+            {+                "cat": 7,+                "x": 0,+                "y": 40+            },+            {+                "cat": 7,+                "x": 1,+                "y": 40+            },+            {+                "cat": 8,+                "x": 0,+                "y": 30+            },+            {+                "cat": 8,+                "x": 1,+                "y": 30+            },+            {+                "cat": 9,+                "x": 0,+                "y": 20+            },+            {+                "cat": 9,+                "x": 1,+                "y": 20+            },+            {+                "cat": 10,+                "x": 0,+                "y": 10+            },+            {+                "cat": 10,+                "x": 1,+                "y": 10+            }+        ]+    },+    "resolve": {+        "scale": {+            "strokeDash": "independent"+        }+    },+    "concat": [+        {+            "mark": "line",+            "width": 200,+            "title": "Nominal",+            "encoding": {+                "strokeDash": {+                    "field": "cat",+                    "scale": {+                        "domain": [+                            0,+                            1,+                            2,+                            3,+                            4,+                            5,+                            6,+                            7,+                            8,+                            9+                        ],+                        "range": [+                            [+                                1,+                                0+                            ],+                            [+                                5,+                                4+                            ],+                            [+                                2,+                                4+                            ],+                            [+                                8,+                                4,+                                4,+                                4+                            ],+                            [+                                1,+                                3+                            ],+                            [+                                16,+                                4+                            ],+                            [+                                6,+                                4+                            ],+                            [+                                8,+                                4+                            ],+                            [+                                4,+                                6+                            ],+                            [+                                10,+                                4+                            ]+                        ]+                    },+                    "type": "nominal"+                },+                "x": {+                    "field": "x",+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": "line",+            "width": 200,+            "title": "Ordinal",+            "encoding": {+                "strokeDash": {+                    "field": "cat",+                    "scale": {+                        "domain": [+                            0,+                            1,+                            2,+                            3,+                            4,+                            5,+                            6,+                            7,+                            8,+                            9+                        ],+                        "range": [+                            [+                                1,+                                0+                            ],+                            [+                                5,+                                4+                            ],+                            [+                                2,+                                4+                            ],+                            [+                                8,+                                4,+                                4,+                                4+                            ],+                            [+                                1,+                                3+                            ],+                            [+                                16,+                                4+                            ],+                            [+                                6,+                                4+                            ],+                            [+                                8,+                                4+                            ],+                            [+                                4,+                                6+                            ],+                            [+                                10,+                                4+                            ]+                        ]+                    },+                    "type": "ordinal"+                },+                "x": {+                    "field": "x",+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "type": "quantitative"+                }+            }+        }+    ],+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json"+}
+ tests/specs/fillstroke/strokedash5.vl view
@@ -0,0 +1,111 @@+{+    "transform": [+        {+            "as": "y0",+            "calculate": "abs(sin(datum.x0+random()))"+        },+        {+            "as": "x",+            "calculate": "datum.x0 %10"+        },+        {+            "as": "cat",+            "calculate": "floor(datum.x0 / 10)"+        },+        {+            "as": "y",+            "calculate": "datum.y0 + datum.cat"+        }+    ],+    "height": 300,+    "mark": "line",+    "data": {+        "sequence": {+            "as": "x0",+            "start": 0,+            "step": 0.1,+            "stop": 100+        }+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Dash scale 0.2",+    "encoding": {+        "strokeDash": {+            "field": "cat",+            "scale": {+                "domain": [+                    0,+                    1,+                    2,+                    3,+                    4,+                    5,+                    6,+                    7,+                    8,+                    9+                ],+                "range": [+                    [+                        0.2,+                        0+                    ],+                    [+                        3.2,+                        0.8+                    ],+                    [+                        2,+                        0.8+                    ],+                    [+                        1.6,+                        0.8+                    ],+                    [+                        1.6,+                        0.8,+                        0.8,+                        0.8+                    ],+                    [+                        1.2000000000000002,+                        0.8+                    ],+                    [+                        1,+                        0.8+                    ],+                    [+                        0.8,+                        1.2000000000000002+                    ],+                    [+                        0.4,+                        0.8+                    ],+                    [+                        0.2,+                        0.6000000000000001+                    ]+                ]+            },+            "type": "ordinal"+        },+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        }+    }+}
+ tests/specs/fillstroke/strokedash6.vl view
@@ -0,0 +1,111 @@+{+    "transform": [+        {+            "as": "y0",+            "calculate": "abs(sin(datum.x0+random()))"+        },+        {+            "as": "x",+            "calculate": "datum.x0 %10"+        },+        {+            "as": "cat",+            "calculate": "floor(datum.x0 / 10)"+        },+        {+            "as": "y",+            "calculate": "datum.y0 + datum.cat"+        }+    ],+    "height": 300,+    "mark": "line",+    "data": {+        "sequence": {+            "as": "x0",+            "start": 0,+            "step": 0.1,+            "stop": 100+        }+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Dash scale 0.5",+    "encoding": {+        "strokeDash": {+            "field": "cat",+            "scale": {+                "domain": [+                    0,+                    1,+                    2,+                    3,+                    4,+                    5,+                    6,+                    7,+                    8,+                    9+                ],+                "range": [+                    [+                        0.5,+                        0+                    ],+                    [+                        8,+                        2+                    ],+                    [+                        5,+                        2+                    ],+                    [+                        4,+                        2+                    ],+                    [+                        4,+                        2,+                        2,+                        2+                    ],+                    [+                        3,+                        2+                    ],+                    [+                        2.5,+                        2+                    ],+                    [+                        2,+                        3+                    ],+                    [+                        1,+                        2+                    ],+                    [+                        0.5,+                        1.5+                    ]+                ]+            },+            "type": "ordinal"+        },+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        }+    }+}
+ tests/specs/fillstroke/strokedash7.vl view
@@ -0,0 +1,111 @@+{+    "transform": [+        {+            "as": "y0",+            "calculate": "abs(sin(datum.x0+random()))"+        },+        {+            "as": "x",+            "calculate": "datum.x0 %10"+        },+        {+            "as": "cat",+            "calculate": "floor(datum.x0 / 10)"+        },+        {+            "as": "y",+            "calculate": "datum.y0 + datum.cat"+        }+    ],+    "height": 300,+    "mark": "line",+    "data": {+        "sequence": {+            "as": "x0",+            "start": 0,+            "step": 0.1,+            "stop": 100+        }+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Dash scale 1.0",+    "encoding": {+        "strokeDash": {+            "field": "cat",+            "scale": {+                "domain": [+                    0,+                    1,+                    2,+                    3,+                    4,+                    5,+                    6,+                    7,+                    8,+                    9+                ],+                "range": [+                    [+                        1,+                        0+                    ],+                    [+                        16,+                        4+                    ],+                    [+                        10,+                        4+                    ],+                    [+                        8,+                        4+                    ],+                    [+                        8,+                        4,+                        4,+                        4+                    ],+                    [+                        6,+                        4+                    ],+                    [+                        5,+                        4+                    ],+                    [+                        4,+                        6+                    ],+                    [+                        2,+                        4+                    ],+                    [+                        1,+                        3+                    ]+                ]+            },+            "type": "ordinal"+        },+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        }+    }+}
+ tests/specs/fillstroke/strokedash8.vl view
@@ -0,0 +1,111 @@+{+    "transform": [+        {+            "as": "y0",+            "calculate": "abs(sin(datum.x0+random()))"+        },+        {+            "as": "x",+            "calculate": "datum.x0 %10"+        },+        {+            "as": "cat",+            "calculate": "floor(datum.x0 / 10)"+        },+        {+            "as": "y",+            "calculate": "datum.y0 + datum.cat"+        }+    ],+    "height": 300,+    "mark": "line",+    "data": {+        "sequence": {+            "as": "x0",+            "start": 0,+            "step": 0.1,+            "stop": 100+        }+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Dash scale 2.0",+    "encoding": {+        "strokeDash": {+            "field": "cat",+            "scale": {+                "domain": [+                    0,+                    1,+                    2,+                    3,+                    4,+                    5,+                    6,+                    7,+                    8,+                    9+                ],+                "range": [+                    [+                        2,+                        0+                    ],+                    [+                        32,+                        8+                    ],+                    [+                        20,+                        8+                    ],+                    [+                        16,+                        8+                    ],+                    [+                        16,+                        8,+                        8,+                        8+                    ],+                    [+                        12,+                        8+                    ],+                    [+                        10,+                        8+                    ],+                    [+                        8,+                        12+                    ],+                    [+                        4,+                        8+                    ],+                    [+                        2,+                        6+                    ]+                ]+            },+            "type": "ordinal"+        },+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        }+    }+}
+ tests/specs/fillstroke/strokedash9.vl view
@@ -0,0 +1,111 @@+{+    "transform": [+        {+            "as": "y0",+            "calculate": "abs(sin(datum.x0+random()))"+        },+        {+            "as": "x",+            "calculate": "datum.x0 %10"+        },+        {+            "as": "cat",+            "calculate": "floor(datum.x0 / 10)"+        },+        {+            "as": "y",+            "calculate": "datum.y0 + datum.cat"+        }+    ],+    "height": 300,+    "mark": "line",+    "data": {+        "sequence": {+            "as": "x0",+            "start": 0,+            "step": 0.1,+            "stop": 100+        }+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Dash scale 4.0",+    "encoding": {+        "strokeDash": {+            "field": "cat",+            "scale": {+                "domain": [+                    0,+                    1,+                    2,+                    3,+                    4,+                    5,+                    6,+                    7,+                    8,+                    9+                ],+                "range": [+                    [+                        4,+                        0+                    ],+                    [+                        64,+                        16+                    ],+                    [+                        40,+                        16+                    ],+                    [+                        32,+                        16+                    ],+                    [+                        32,+                        16,+                        16,+                        16+                    ],+                    [+                        24,+                        16+                    ],+                    [+                        20,+                        16+                    ],+                    [+                        16,+                        24+                    ],+                    [+                        8,+                        16+                    ],+                    [+                        4,+                        12+                    ]+                ]+            },+            "type": "ordinal"+        },+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "grid": false+            }+        }+    }+}
+ tests/specs/fillstroke/vrounded.vl view
@@ -0,0 +1,57 @@+{+    "mark": {+        "cornerRadiusEnd": 4,+        "type": "bar"+    },+    "data": {+        "values": [+            {+                "a": "A",+                "b": 28+            },+            {+                "a": "B",+                "b": 55+            },+            {+                "a": "C",+                "b": 43+            },+            {+                "a": "D",+                "b": 91+            },+            {+                "a": "E",+                "b": 81+            },+            {+                "a": "F",+                "b": 53+            },+            {+                "a": "G",+                "b": 19+            },+            {+                "a": "H",+                "b": 87+            },+            {+                "a": "I",+                "b": 52+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "a",+            "type": "ordinal"+        },+        "y": {+            "field": "b",+            "type": "quantitative"+        }+    }+}
tests/specs/gallery/facet/facet7.vl view
@@ -26,7 +26,13 @@             "field": "symbol",             "header": {                 "labelAngle": 0,-                "title": "Stock price",+                "labelFontStyle": "italic",+                "labelExpr": "'{' + datum.label + '}'",+                "titleLineHeight": 20,+                "title": [+                    "Stock",+                    "price"+                ],                 "labelAlign": "left"             },             "type": "nominal"
+ tests/specs/gallery/label/baselines.vl view
@@ -0,0 +1,183 @@+{+    "config": {+        "mark": {+            "fontSize": 20+        }+    },+    "data": {+        "values": [+            {+                "x": 10,+                "y": 10+            },+            {+                "x": 20,+                "y": 20+            }+        ]+    },+    "concat": [+        {+            "mark": {+                "type": "text",+                "baseline": "top"+            },+            "title": "top",+            "encoding": {+                "text": {+                    "value": "Xxgq"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                }+            }+        },+        {+            "mark": {+                "type": "text",+                "baseline": "middle"+            },+            "title": "middle",+            "encoding": {+                "text": {+                    "value": "Xxgq"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                }+            }+        },+        {+            "mark": {+                "type": "text",+                "baseline": "alphabetic"+            },+            "title": "baseline",+            "encoding": {+                "text": {+                    "value": "Xxgq"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                }+            }+        },+        {+            "mark": {+                "type": "text",+                "baseline": "bottom"+            },+            "title": "bottom",+            "encoding": {+                "text": {+                    "value": "Xxgq"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            5,+                            25+                        ],+                        "nice": false+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                }+            }+        }+    ],+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "columns": 2+}
tests/specs/gallery/label/label2.vl view
@@ -4,6 +4,7 @@             "baseline": "middle"         },         "scale": {+            "xReverse": false,             "bandPaddingInner": 0,             "bandPaddingOuter": 0         }
+ tests/specs/gallery/label/label2r.vl view
@@ -0,0 +1,52 @@+{+    "config": {+        "text": {+            "baseline": "middle"+        },+        "scale": {+            "xReverse": true,+            "bandPaddingInner": 0,+            "bandPaddingOuter": 0+        }+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": "rect",+            "encoding": {+                "color": {+                    "field": "*",+                    "aggregate": "count",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": "text",+            "encoding": {+                "color": {+                    "value": "white"+                },+                "text": {+                    "field": "*",+                    "aggregate": "count",+                    "type": "quantitative"+                }+            }+        }+    ],+    "encoding": {+        "x": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "y": {+            "field": "Origin",+            "type": "ordinal"+        }+    },+    "description": "Layering text over 'heatmap'"+}
tests/specs/gallery/label/label3.vl view
@@ -149,7 +149,7 @@             },             "type": "quantitative",             "axis": {-                "title": "CO2 concentration in ppm"+                "title": "CO₂ concentration in ppm"             }         }     },
+ tests/specs/gallery/label/label8.vl view
@@ -0,0 +1,1026 @@+{+    "height": 175,+    "config": {+        "view": {+            "stroke": null+        }+    },+    "data": {+        "name": "medians"+    },+    "width": 250,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Questionnaire Ratings",+    "layer": [+        {+            "transform": [+                {+                    "filter": "datum.name != 'Toolbar_First'"+                },+                {+                    "filter": "datum.name != 'Tablet_First'"+                },+                {+                    "filter": "datum.name != 'Participant ID'"+                }+            ],+            "mark": {+                "color": "#6eb4fd",+                "type": "circle"+            },+            "data": {+                "name": "values"+            },+            "encoding": {+                "size": {+                    "aggregate": "count",+                    "type": "quantitative",+                    "legend": {+                        "offset": 75,+                        "title": "Number of Ratings"+                    }+                },+                "x": {+                    "field": "value",+                    "scale": {+                        "domain": [+                            0,+                            6+                        ]+                    },+                    "type": "quantitative",+                    "axis": {+                        "values": [+                            1,+                            2,+                            3,+                            4,+                            5+                        ],+                        "grid": false+                    }+                }+            }+        },+        {+            "mark": {+                "color": "black",+                "type": "tick"+            },+            "encoding": {+                "x": {+                    "field": "median",+                    "scale": {+                        "domain": [+                            0,+                            6+                        ]+                    },+                    "type": "quantitative",+                    "axis": {+                        "title": null+                    }+                }+            }+        },+        {+            "mark": {+                "align": "right",+                "x": -5,+                "type": "text"+            },+            "encoding": {+                "text": {+                    "field": "lo",+                    "type": "nominal"+                }+            }+        },+        {+            "mark": {+                "align": "left",+                "x": 255,+                "type": "text"+            },+            "encoding": {+                "text": {+                    "field": "hi",+                    "type": "nominal"+                }+            }+        }+    ],+    "encoding": {+        "y": {+            "field": "name",+            "sort": null,+            "type": "nominal",+            "axis": {+                "offset": 50,+                "domain": false,+                "labelFontWeight": "bold",+                "grid": true,+                "title": null,+                "ticks": false+            }+        }+    },+    "datasets": {+        "values": [+            {+                "value": "P1",+                "name": "Participant ID",+                "id": "P1"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P1"+            },+            {+                "value": "2",+                "name": "Fix Errors:",+                "id": "P1"+            },+            {+                "value": "3",+                "name": "Easier to Fix:",+                "id": "P1"+            },+            {+                "value": "4",+                "name": "Faster to Fix:",+                "id": "P1"+            },+            {+                "value": "2",+                "name": "Easier on Phone:",+                "id": "P1"+            },+            {+                "value": "5",+                "name": "Easier on Tablet:",+                "id": "P1"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P1"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P1"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P1"+            },+            {+                "value": "P2",+                "name": "Participant ID",+                "id": "P2"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P2"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P2"+            },+            {+                "value": "4",+                "name": "Easier to Fix:",+                "id": "P2"+            },+            {+                "value": "5",+                "name": "Faster to Fix:",+                "id": "P2"+            },+            {+                "value": "5",+                "name": "Easier on Phone:",+                "id": "P2"+            },+            {+                "value": "5",+                "name": "Easier on Tablet:",+                "id": "P2"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P2"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P2"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P2"+            },+            {+                "value": "P3",+                "name": "Participant ID",+                "id": "P3"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P3"+            },+            {+                "value": "2",+                "name": "Fix Errors:",+                "id": "P3"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P3"+            },+            {+                "value": "1",+                "name": "Faster to Fix:",+                "id": "P3"+            },+            {+                "value": "2",+                "name": "Easier on Phone:",+                "id": "P3"+            },+            {+                "value": "1",+                "name": "Easier on Tablet:",+                "id": "P3"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P3"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P3"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P3"+            },+            {+                "value": "P4",+                "name": "Participant ID",+                "id": "P4"+            },+            {+                "value": "3",+                "name": "Identify Errors:",+                "id": "P4"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P4"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P4"+            },+            {+                "value": "2",+                "name": "Faster to Fix:",+                "id": "P4"+            },+            {+                "value": "4",+                "name": "Easier on Phone:",+                "id": "P4"+            },+            {+                "value": "1",+                "name": "Easier on Tablet:",+                "id": "P4"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P4"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P4"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P4"+            },+            {+                "value": "P5",+                "name": "Participant ID",+                "id": "P5"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P5"+            },+            {+                "value": "2",+                "name": "Fix Errors:",+                "id": "P5"+            },+            {+                "value": "4",+                "name": "Easier to Fix:",+                "id": "P5"+            },+            {+                "value": "4",+                "name": "Faster to Fix:",+                "id": "P5"+            },+            {+                "value": "4",+                "name": "Easier on Phone:",+                "id": "P5"+            },+            {+                "value": "5",+                "name": "Easier on Tablet:",+                "id": "P5"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P5"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P5"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P5"+            },+            {+                "value": "P6",+                "name": "Participant ID",+                "id": "P6"+            },+            {+                "value": "1",+                "name": "Identify Errors:",+                "id": "P6"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P6"+            },+            {+                "value": "3",+                "name": "Easier to Fix:",+                "id": "P6"+            },+            {+                "value": "4",+                "name": "Faster to Fix:",+                "id": "P6"+            },+            {+                "value": "4",+                "name": "Easier on Phone:",+                "id": "P6"+            },+            {+                "value": "4",+                "name": "Easier on Tablet:",+                "id": "P6"+            },+            {+                "value": "4",+                "name": "Device Preference:",+                "id": "P6"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P6"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P6"+            },+            {+                "value": "P7",+                "name": "Participant ID",+                "id": "P7"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P7"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P7"+            },+            {+                "value": "4",+                "name": "Easier to Fix:",+                "id": "P7"+            },+            {+                "value": "5",+                "name": "Faster to Fix:",+                "id": "P7"+            },+            {+                "value": "3",+                "name": "Easier on Phone:",+                "id": "P7"+            },+            {+                "value": "2",+                "name": "Easier on Tablet:",+                "id": "P7"+            },+            {+                "value": "4",+                "name": "Device Preference:",+                "id": "P7"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P7"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P7"+            },+            {+                "value": "P8",+                "name": "Participant ID",+                "id": "P8"+            },+            {+                "value": "3",+                "name": "Identify Errors:",+                "id": "P8"+            },+            {+                "value": "1",+                "name": "Fix Errors:",+                "id": "P8"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P8"+            },+            {+                "value": "4",+                "name": "Faster to Fix:",+                "id": "P8"+            },+            {+                "value": "2",+                "name": "Easier on Phone:",+                "id": "P8"+            },+            {+                "value": "5",+                "name": "Easier on Tablet:",+                "id": "P8"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P8"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P8"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P8"+            },+            {+                "value": "P9",+                "name": "Participant ID",+                "id": "P9"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P9"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P9"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P9"+            },+            {+                "value": "4",+                "name": "Faster to Fix:",+                "id": "P9"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P9"+            },+            {+                "value": "4",+                "name": "Easier on Tablet:",+                "id": "P9"+            },+            {+                "value": "4",+                "name": "Device Preference:",+                "id": "P9"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P9"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P9"+            },+            {+                "value": "P10",+                "name": "Participant ID",+                "id": "P10"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P10"+            },+            {+                "value": "2",+                "name": "Fix Errors:",+                "id": "P10"+            },+            {+                "value": "1",+                "name": "Easier to Fix:",+                "id": "P10"+            },+            {+                "value": "1",+                "name": "Faster to Fix:",+                "id": "P10"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P10"+            },+            {+                "value": "1",+                "name": "Easier on Tablet:",+                "id": "P10"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P10"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P10"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P10"+            },+            {+                "value": "P11",+                "name": "Participant ID",+                "id": "P11"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P11"+            },+            {+                "value": "2",+                "name": "Fix Errors:",+                "id": "P11"+            },+            {+                "value": "1",+                "name": "Easier to Fix:",+                "id": "P11"+            },+            {+                "value": "1",+                "name": "Faster to Fix:",+                "id": "P11"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P11"+            },+            {+                "value": "1",+                "name": "Easier on Tablet:",+                "id": "P11"+            },+            {+                "value": "4",+                "name": "Device Preference:",+                "id": "P11"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P11"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P11"+            },+            {+                "value": "P12",+                "name": "Participant ID",+                "id": "P12"+            },+            {+                "value": "1",+                "name": "Identify Errors:",+                "id": "P12"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P12"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P12"+            },+            {+                "value": "3",+                "name": "Faster to Fix:",+                "id": "P12"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P12"+            },+            {+                "value": "3",+                "name": "Easier on Tablet:",+                "id": "P12"+            },+            {+                "value": "3",+                "name": "Device Preference:",+                "id": "P12"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P12"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P12"+            },+            {+                "value": "P13",+                "name": "Participant ID",+                "id": "P13"+            },+            {+                "value": "2",+                "name": "Identify Errors:",+                "id": "P13"+            },+            {+                "value": "2",+                "name": "Fix Errors:",+                "id": "P13"+            },+            {+                "value": "1",+                "name": "Easier to Fix:",+                "id": "P13"+            },+            {+                "value": "1",+                "name": "Faster to Fix:",+                "id": "P13"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P13"+            },+            {+                "value": "1",+                "name": "Easier on Tablet:",+                "id": "P13"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P13"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P13"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P13"+            },+            {+                "value": "P14",+                "name": "Participant ID",+                "id": "P14"+            },+            {+                "value": "3",+                "name": "Identify Errors:",+                "id": "P14"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P14"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P14"+            },+            {+                "value": "2",+                "name": "Faster to Fix:",+                "id": "P14"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P14"+            },+            {+                "value": "1",+                "name": "Easier on Tablet:",+                "id": "P14"+            },+            {+                "value": "1",+                "name": "Device Preference:",+                "id": "P14"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P14"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P14"+            },+            {+                "value": "P15",+                "name": "Participant ID",+                "id": "P15"+            },+            {+                "value": "4",+                "name": "Identify Errors:",+                "id": "P15"+            },+            {+                "value": "5",+                "name": "Fix Errors:",+                "id": "P15"+            },+            {+                "value": "1",+                "name": "Easier to Fix:",+                "id": "P15"+            },+            {+                "value": "1",+                "name": "Faster to Fix:",+                "id": "P15"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P15"+            },+            {+                "value": "1",+                "name": "Easier on Tablet:",+                "id": "P15"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P15"+            },+            {+                "value": "1",+                "name": "Tablet_First",+                "id": "P15"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P15"+            },+            {+                "value": "P16",+                "name": "Participant ID",+                "id": "P16"+            },+            {+                "value": "1",+                "name": "Identify Errors:",+                "id": "P16"+            },+            {+                "value": "3",+                "name": "Fix Errors:",+                "id": "P16"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P16"+            },+            {+                "value": "2",+                "name": "Faster to Fix:",+                "id": "P16"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P16"+            },+            {+                "value": "4",+                "name": "Easier on Tablet:",+                "id": "P16"+            },+            {+                "value": "5",+                "name": "Device Preference:",+                "id": "P16"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P16"+            },+            {+                "value": "1",+                "name": "Toolbar_First",+                "id": "P16"+            },+            {+                "value": "P17",+                "name": "Participant ID",+                "id": "P17"+            },+            {+                "value": "3",+                "name": "Identify Errors:",+                "id": "P17"+            },+            {+                "value": "2",+                "name": "Fix Errors:",+                "id": "P17"+            },+            {+                "value": "2",+                "name": "Easier to Fix:",+                "id": "P17"+            },+            {+                "value": "2",+                "name": "Faster to Fix:",+                "id": "P17"+            },+            {+                "value": "1",+                "name": "Easier on Phone:",+                "id": "P17"+            },+            {+                "value": "3",+                "name": "Easier on Tablet:",+                "id": "P17"+            },+            {+                "value": "2",+                "name": "Device Preference:",+                "id": "P17"+            },+            {+                "value": "0",+                "name": "Tablet_First",+                "id": "P17"+            },+            {+                "value": "0",+                "name": "Toolbar_First",+                "id": "P17"+            }+        ],+        "medians": [+            {+                "median": 1.999976,+                "hi": "Hard",+                "name": "Identify Errors:",+                "lo": "Easy"+            },+            {+                "median": 2,+                "hi": "Hard",+                "name": "Fix Errors:",+                "lo": "Easy"+            },+            {+                "median": 1.999969,+                "hi": "Gesture",+                "name": "Easier to Fix:",+                "lo": "Toolbar"+            },+            {+                "median": 2.500045,+                "hi": "Gesture",+                "name": "Faster to Fix:",+                "lo": "Toolbar"+            },+            {+                "median": 1.500022,+                "hi": "Gesture",+                "name": "Easier on Phone:",+                "lo": "Toolbar"+            },+            {+                "median": 2.99998,+                "hi": "Gesture",+                "name": "Easier on Tablet:",+                "lo": "Toolbar"+            },+            {+                "median": 4.500007,+                "hi": "Tablet",+                "name": "Device Preference:",+                "lo": "Phone"+            }+        ]+    }+}
+ tests/specs/gallery/label/label9.vl view
@@ -0,0 +1,280 @@+{+    "config": {+        "style": {+            "arrow-label2": {+                "dy": 24,+                "fontSize": 9.5+            },+            "arrow-label": {+                "dy": 12,+                "fontSize": 9.5+            }+        },+        "view": {+            "stroke": null+        },+        "title": {+            "fontSize": 12+        }+    },+    "data": {+        "values": [+            {+                "mean": 1.81,+                "hi": 2.37,+                "study": "PoleStar vs Voyager",+                "measure": "Open Exploration",+                "lo": 1.26+            },+            {+                "mean": -1.69,+                "hi": -1.05,+                "study": "PoleStar vs Voyager",+                "measure": "Focused Question Answering",+                "lo": -2.33+            },+            {+                "mean": 2.19,+                "hi": 2.71,+                "study": "PoleStar vs Voyager 2",+                "measure": "Open Exploration",+                "lo": 1.67+            },+            {+                "mean": -6.0e-2,+                "hi": 0.35,+                "study": "PoleStar vs Voyager 2",+                "measure": "Focused Question Answering",+                "lo": -0.47+            }+        ]+    },+    "vconcat": [+        {+            "title": {+                "text": "Mean of Subject Ratings (95% CIs)",+                "frame": "bounds"+            },+            "layer": [+                {+                    "mark": "rule",+                    "encoding": {+                        "x2": {+                            "field": "hi"+                        },+                        "x": {+                            "field": "lo",+                            "scale": {+                                "domain": [+                                    -3,+                                    3+                                ]+                            },+                            "type": "quantitative",+                            "axis": {+                                "gridDash": [+                                    3,+                                    3+                                ],+                                "gridColor": {+                                    "value": "#ccc",+                                    "condition": {+                                        "value": "#666",+                                        "test": "datum.value === 0"+                                    }+                                },+                                "title": null+                            }+                        }+                    }+                },+                {+                    "mark": {+                        "opacity": 1,+                        "stroke": "black",+                        "type": "circle"+                    },+                    "encoding": {+                        "color": {+                            "field": "measure",+                            "scale": {+                                "range": [+                                    "black",+                                    "white"+                                ]+                            },+                            "type": "nominal",+                            "legend": null+                        },+                        "x": {+                            "field": "mean",+                            "type": "quantitative"+                        }+                    }+                }+            ],+            "encoding": {+                "y": {+                    "field": "study",+                    "type": "nominal",+                    "axis": {+                        "domain": false,+                        "labelPadding": 5,+                        "grid": false,+                        "title": null,+                        "ticks": false+                    }+                }+            }+        },+        {+            "data": {+                "values": [+                    {+                        "to": -2.9,+                        "from": -0.25,+                        "label": "PoleStar"+                    },+                    {+                        "to": 2.9,+                        "from": 0.25,+                        "label": "Voyager / Voyager 2"+                    }+                ]+            },+            "layer": [+                {+                    "mark": "rule",+                    "encoding": {+                        "x2": {+                            "field": "to"+                        },+                        "x": {+                            "field": "from",+                            "scale": {+                                "zero": false+                            },+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "mark": {+                        "size": 60,+                        "fill": "black",+                        "type": "point",+                        "filled": true+                    },+                    "encoding": {+                        "shape": {+                            "value": "triangle-left",+                            "condition": {+                                "value": "triangle-right",+                                "test": "datum.to > 0"+                            }+                        },+                        "x": {+                            "field": "to",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "transform": [+                        {+                            "filter": "datum.label === 'PoleStar'"+                        }+                    ],+                    "mark": {+                        "style": "arrow-label",+                        "align": "right",+                        "type": "text"+                    },+                    "encoding": {+                        "text": {+                            "field": "label",+                            "type": "nominal"+                        },+                        "x": {+                            "field": "from",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "transform": [+                        {+                            "filter": "datum.label !== 'PoleStar'"+                        }+                    ],+                    "mark": {+                        "style": "arrow-label",+                        "align": "left",+                        "type": "text"+                    },+                    "encoding": {+                        "text": {+                            "field": "label",+                            "type": "nominal"+                        },+                        "x": {+                            "field": "from",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "transform": [+                        {+                            "filter": "datum.label === 'PoleStar'"+                        }+                    ],+                    "mark": {+                        "style": "arrow-label2",+                        "align": "right",+                        "type": "text"+                    },+                    "encoding": {+                        "text": {+                            "value": "more valuable"+                        },+                        "x": {+                            "field": "from",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "transform": [+                        {+                            "filter": "datum.label !== 'PoleStar'"+                        }+                    ],+                    "mark": {+                        "style": "arrow-label2",+                        "align": "left",+                        "type": "text"+                    },+                    "encoding": {+                        "text": {+                            "value": "more valuable"+                        },+                        "x": {+                            "field": "from",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                }+            ]+        }+    ],+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "description": "Comparing Likert scale ratings between two conditions.",+    "spacing": 10+}
+ tests/specs/gallery/label/voyager.vl view
@@ -0,0 +1,235 @@+{+    "config": {+        "style": {+            "arrow-label2": {+                "dy": 24,+                "fontSize": 9.5+            },+            "arrow-label": {+                "dy": 12,+                "fontSize": 9.5+            }+        },+        "view": {+            "stroke": "transparent"+        },+        "title": {+            "fontSize": 12+        }+    },+    "data": {+        "values": [+            {+                "mean": 1.813,+                "hi": 2.37,+                "study": "PoleStar vs Voyager",+                "measure": "Open Exploration",+                "lo": 1.255+            },+            {+                "mean": -1.688,+                "hi": -1.05,+                "study": "PoleStar vs Voyager",+                "measure": "Focused Question Answering",+                "lo": -2.325+            },+            {+                "mean": 2.1875,+                "hi": 2.71,+                "study": "PoleStar vs Voyager 2",+                "measure": "Open Exploration",+                "lo": 1.665+            },+            {+                "mean": -6.25e-2,+                "hi": 0.349,+                "study": "PoleStar vs Voyager 2",+                "measure": "Focused Question Answering",+                "lo": -0.474+            }+        ]+    },+    "vconcat": [+        {+            "title": {+                "text": "Mean of Subject Ratings (95% CIs)",+                "frame": "bounds"+            },+            "layer": [+                {+                    "mark": "rule",+                    "encoding": {+                        "x2": {+                            "field": "hi"+                        },+                        "x": {+                            "field": "lo",+                            "scale": {+                                "domain": [+                                    -3,+                                    3+                                ]+                            },+                            "type": "quantitative",+                            "axis": {+                                "gridDash": [+                                    3,+                                    3+                                ],+                                "gridColor": {+                                    "value": "#CCC",+                                    "condition": {+                                        "value": "#666",+                                        "test": "datum.value === 0"+                                    }+                                },+                                "title": ""+                            }+                        }+                    }+                },+                {+                    "mark": {+                        "opacity": 1,+                        "stroke": "black",+                        "type": "circle"+                    },+                    "encoding": {+                        "color": {+                            "field": "measure",+                            "scale": {+                                "range": [+                                    "black",+                                    "white"+                                ]+                            },+                            "type": "nominal",+                            "legend": null+                        },+                        "x": {+                            "field": "mean",+                            "type": "quantitative"+                        }+                    }+                }+            ],+            "encoding": {+                "y": {+                    "field": "study",+                    "type": "nominal",+                    "axis": {+                        "domain": false,+                        "labelPadding": 5,+                        "grid": false,+                        "title": null,+                        "ticks": false+                    }+                }+            }+        },+        {+            "data": {+                "values": [+                    {+                        "to": -2.9,+                        "from": -0.25,+                        "label": "PoleStar"+                    },+                    {+                        "to": 2.9,+                        "from": 0.25,+                        "label": "Voyager / Voyager 2"+                    }+                ]+            },+            "layer": [+                {+                    "mark": "rule",+                    "encoding": {+                        "x2": {+                            "field": "to"+                        },+                        "x": {+                            "field": "from",+                            "scale": {+                                "zero": false+                            },+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "mark": {+                        "size": 60,+                        "fill": "black",+                        "type": "point",+                        "filled": true+                    },+                    "encoding": {+                        "shape": {+                            "value": "triangle-left",+                            "condition": {+                                "value": "triangle-right",+                                "test": "datum.to > 0"+                            }+                        },+                        "x": {+                            "field": "to",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "transform": [+                        {+                            "filter": "datum.label === 'PoleStar'"+                        }+                    ],+                    "mark": {+                        "style": "arrow-label",+                        "text": [+                            "Polestar",+                            "More Valuable"+                        ],+                        "align": "right",+                        "type": "text"+                    },+                    "encoding": {+                        "x": {+                            "field": "from",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                },+                {+                    "transform": [+                        {+                            "filter": "datum.label !== 'PoleStar'"+                        }+                    ],+                    "mark": {+                        "style": "arrow-label",+                        "text": [+                            "Voyager / Voyager 2",+                            "More Valuable"+                        ],+                        "align": "left",+                        "type": "text"+                    },+                    "encoding": {+                        "x": {+                            "field": "from",+                            "type": "quantitative",+                            "axis": null+                        }+                    }+                }+            ]+        }+    ],+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "spacing": 10+}
tests/specs/gallery/layer/layer6.vl view
@@ -5,10 +5,19 @@     },     "width": 250,     "$schema": "https://vega.github.io/schema/vega-lite/v4.json",-    "title": "Weekly Weather Observations and Predictions",+    "title": {+        "text": [+            "Weekly Weather",+            "Observations and Predictions"+        ],+        "frame": "group"+    },     "layer": [         {-            "mark": "bar",+            "mark": {+                "style": "box",+                "type": "bar"+            },             "encoding": {                 "color": {                     "value": "#ccc"@@ -16,13 +25,6 @@                 "size": {                     "value": 20                 },-                "x": {-                    "field": "id",-                    "type": "ordinal",-                    "axis": {-                        "title": "Day"-                    }-                },                 "y2": {                     "field": "record.high"                 },@@ -42,7 +44,10 @@             }         },         {-            "mark": "bar",+            "mark": {+                "style": "box",+                "type": "bar"+            },             "encoding": {                 "color": {                     "value": "#999"@@ -50,10 +55,6 @@                 "size": {                     "value": 20                 },-                "x": {-                    "field": "id",-                    "type": "ordinal"-                },                 "y2": {                     "field": "normal.high"                 },@@ -64,7 +65,10 @@             }         },         {-            "mark": "bar",+            "mark": {+                "style": "box",+                "type": "bar"+            },             "encoding": {                 "color": {                     "value": "#000"@@ -72,10 +76,6 @@                 "size": {                     "value": 12                 },-                "x": {-                    "field": "id",-                    "type": "ordinal"-                },                 "y2": {                     "field": "actual.high"                 },@@ -86,7 +86,10 @@             }         },         {-            "mark": "bar",+            "mark": {+                "style": "box",+                "type": "bar"+            },             "encoding": {                 "color": {                     "value": "#000"@@ -94,10 +97,6 @@                 "size": {                     "value": 12                 },-                "x": {-                    "field": "id",-                    "type": "ordinal"-                },                 "y2": {                     "field": "forecast.low.high"                 },@@ -108,7 +107,10 @@             }         },         {-            "mark": "bar",+            "mark": {+                "style": "box",+                "type": "bar"+            },             "encoding": {                 "color": {                     "value": "#000"@@ -116,10 +118,6 @@                 "size": {                     "value": 3                 },-                "x": {-                    "field": "id",-                    "type": "ordinal"-                },                 "y2": {                     "field": "forecast.high.low"                 },@@ -130,7 +128,10 @@             }         },         {-            "mark": "bar",+            "mark": {+                "style": "box",+                "type": "bar"+            },             "encoding": {                 "color": {                     "value": "#000"@@ -138,10 +139,6 @@                 "size": {                     "value": 12                 },-                "x": {-                    "field": "id",-                    "type": "ordinal"-                },                 "y2": {                     "field": "forecast.high.high"                 },@@ -153,29 +150,32 @@         },         {             "mark": {-                "dy": -105,                 "align": "center",-                "type": "text"+                "type": "text",+                "baseline": "bottom",+                "y": -5             },             "encoding": {                 "text": {                     "field": "day",                     "type": "nominal"-                },-                "x": {-                    "field": "id",-                    "type": "ordinal",-                    "axis": {-                        "domain": false,-                        "orient": "top",-                        "titlePadding": 25,-                        "labels": false,-                        "title": "Day",-                        "ticks": false-                    }                 }             }         }     ],+    "encoding": {+        "x": {+            "field": "id",+            "type": "ordinal",+            "axis": {+                "domain": false,+                "orient": "top",+                "titlePadding": 25,+                "labels": false,+                "title": null,+                "ticks": false+            }+        }+    },     "description": "A layered bar chart with floating bars representing weekly weather data" }
tests/specs/gallery/multi/multi4.vl view
@@ -20,13 +20,14 @@             "layer": [                 {                     "mark": "rect",-                    "width": 300,                     "encoding": {                         "color": {                             "aggregate": "count",                             "type": "quantitative",                             "legend": {-                                "title": null+                                "direction": "horizontal",+                                "gradientLength": 120,+                                "title": "All Movies"                             }                         }                     }@@ -74,7 +75,7 @@         {             "height": 120,             "mark": "bar",-            "width": 420,+            "width": 330,             "selection": {                 "myPts": {                     "encodings": [
tests/specs/geo/mapComp3.vl view
@@ -1,9 +1,10 @@ {     "hconcat": [         {+            "height": 300,+            "width": 300,             "layer": [                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.1,                         "stroke": "#411",@@ -17,7 +18,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -28,7 +28,6 @@                     }                 },                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.5,                         "stroke": "white",@@ -42,7 +41,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -55,9 +53,10 @@             ]         },         {+            "height": 300,+            "width": 300,             "layer": [                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.1,                         "stroke": "#411",@@ -71,7 +70,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -82,7 +80,6 @@                     }                 },                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.5,                         "stroke": "white",@@ -96,7 +93,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -109,9 +105,10 @@             ]         },         {+            "height": 300,+            "width": 300,             "layer": [                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.1,                         "stroke": "#411",@@ -125,18 +122,16 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [-                            -65,+                            10,                             0,                             0                         ]                     }                 },                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.5,                         "stroke": "white",@@ -150,11 +145,10 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [-                            -65,+                            10,                             0,                             0                         ]
tests/specs/geo/mapComp4.vl view
@@ -1,9 +1,10 @@ {     "hconcat": [         {+            "height": 300,+            "width": 300,             "layer": [                 {-                    "height": 300,                     "mark": {                         "fill": "#c1e7f5",                         "strokeOpacity": 0,@@ -16,7 +17,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -27,7 +27,6 @@                     }                 },                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.1,                         "stroke": "#411",@@ -41,7 +40,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -52,7 +50,6 @@                     }                 },                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.1,                         "stroke": "white",@@ -66,7 +63,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -79,9 +75,10 @@             ]         },         {+            "height": 300,+            "width": 300,             "layer": [                 {-                    "height": 300,                     "mark": {                         "fill": "#c1e7f5",                         "strokeOpacity": 0,@@ -94,7 +91,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -105,7 +101,6 @@                     }                 },                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.1,                         "stroke": "#411",@@ -119,7 +114,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [@@ -130,7 +124,6 @@                     }                 },                 {-                    "height": 300,                     "mark": {                         "strokeWidth": 0.1,                         "stroke": "white",@@ -144,7 +137,6 @@                             "type": "topojson"                         }                     },-                    "width": 300,                     "projection": {                         "type": "orthographic",                         "rotate": [
+ tests/specs/interaction/curhelp.vl view
@@ -0,0 +1,45 @@+{+    "transform": [+        {+            "filter": "datum.symbol==='GOOG'"+        }+    ],+    "config": {+        "view": {+            "cursor": "text"+        }+    },+    "mark": "line",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/stocks.csv",+        "format": {+            "parse": {+                "date": "date"+            },+            "type": "csv"+        }+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "myBrush": {+            "mark": {+                "cursor": "help"+            },+            "encodings": [+                "x"+            ],+            "type": "interval"+        }+    },+    "encoding": {+        "x": {+            "field": "date",+            "type": "temporal"+        },+        "y": {+            "field": "price",+            "type": "quantitative"+        }+    }+}
+ tests/specs/interaction/curpointer.vl view
@@ -0,0 +1,45 @@+{+    "transform": [+        {+            "filter": "datum.symbol==='GOOG'"+        }+    ],+    "config": {+        "view": {+            "cursor": "text"+        }+    },+    "mark": "line",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/stocks.csv",+        "format": {+            "parse": {+                "date": "date"+            },+            "type": "csv"+        }+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "myBrush": {+            "mark": {+                "cursor": "pointer"+            },+            "encodings": [+                "x"+            ],+            "type": "interval"+        }+    },+    "encoding": {+        "x": {+            "field": "date",+            "type": "temporal"+        },+        "y": {+            "field": "price",+            "type": "quantitative"+        }+    }+}
+ tests/specs/legend/limits1.vl view
@@ -0,0 +1,55 @@+{+    "height": 300,+    "config": {+        "legend": {+            "symbolLimit": 1,+            "unselectedOpacity": 0.1+        }+    },+    "mark": {+        "type": "point",+        "filled": true+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "sel": {+            "bind": {+                "legend": "dblclick"+            },+            "type": "multi",+            "on": "click",+            "fields": [+                "Origin"+            ]+        }+    },+    "encoding": {+        "color": {+            "field": "Origin",+            "type": "nominal"+        },+        "size": {+            "value": 20,+            "condition": {+                "value": 100,+                "selection": "sel"+            }+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/legend/limits2.vl view
@@ -0,0 +1,55 @@+{+    "height": 300,+    "config": {+        "legend": {+            "symbolLimit": 2,+            "unselectedOpacity": 0.1+        }+    },+    "mark": {+        "type": "point",+        "filled": true+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "sel": {+            "bind": {+                "legend": "dblclick"+            },+            "type": "multi",+            "on": "click",+            "fields": [+                "Origin"+            ]+        }+    },+    "encoding": {+        "color": {+            "field": "Origin",+            "type": "nominal"+        },+        "size": {+            "value": 20,+            "condition": {+                "value": 100,+                "selection": "sel"+            }+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/legend/limits3.vl view
@@ -0,0 +1,55 @@+{+    "height": 300,+    "config": {+        "legend": {+            "symbolLimit": 3,+            "unselectedOpacity": 0.1+        }+    },+    "mark": {+        "type": "point",+        "filled": true+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "sel": {+            "bind": {+                "legend": "dblclick"+            },+            "type": "multi",+            "on": "click",+            "fields": [+                "Origin"+            ]+        }+    },+    "encoding": {+        "color": {+            "field": "Origin",+            "type": "nominal"+        },+        "size": {+            "value": 20,+            "condition": {+                "value": 100,+                "selection": "sel"+            }+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
tests/specs/position/position10.vl view
@@ -17,11 +17,11 @@             },             {                 "cat": 4,-                "val": 20+                "val": 15             },             {                 "cat": 5,-                "val": 10+                "val": 12             }         ]     },
+ tests/specs/position/position10r.vl view
@@ -0,0 +1,45 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "empty": 0,+                "cat": 1,+                "val": 10+            },+            {+                "cat": 2,+                "val": 20+            },+            {+                "cat": 3,+                "val": 30+            },+            {+                "cat": 4,+                "val": 15+            },+            {+                "cat": 5,+                "val": 12+            }+        ]+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "scale": {+                "paddingInner": 0.5,+                "align": 0.5,+                "reverse": true+            },+            "type": "ordinal"+        },+        "y": {+            "field": "val",+            "type": "quantitative"+        }+    }+}
tests/specs/position/position11.vl view
@@ -17,11 +17,11 @@             },             {                 "cat": 4,-                "val": 20+                "val": 15             },             {                 "cat": 5,-                "val": 10+                "val": 12             }         ]     },
+ tests/specs/position/position11r.vl view
@@ -0,0 +1,45 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "empty": 0,+                "cat": 1,+                "val": 10+            },+            {+                "cat": 2,+                "val": 20+            },+            {+                "cat": 3,+                "val": 30+            },+            {+                "cat": 4,+                "val": 15+            },+            {+                "cat": 5,+                "val": 12+            }+        ]+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "scale": {+                "paddingInner": 0.5,+                "align": 0.7,+                "reverse": true+            },+            "type": "ordinal"+        },+        "y": {+            "field": "val",+            "type": "quantitative"+        }+    }+}
tests/specs/position/position12.vl view
@@ -17,11 +17,11 @@             },             {                 "cat": 4,-                "val": 20+                "val": 15             },             {                 "cat": 5,-                "val": 10+                "val": 12             }         ]     },
+ tests/specs/position/position12r.vl view
@@ -0,0 +1,45 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "empty": 0,+                "cat": 1,+                "val": 10+            },+            {+                "cat": 2,+                "val": 20+            },+            {+                "cat": 3,+                "val": 30+            },+            {+                "cat": 4,+                "val": 15+            },+            {+                "cat": 5,+                "val": 12+            }+        ]+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "scale": {+                "paddingInner": 0.5,+                "align": 1,+                "reverse": true+            },+            "type": "ordinal"+        },+        "y": {+            "field": "val",+            "type": "quantitative"+        }+    }+}
tests/specs/position/position6.vl view
@@ -20,11 +20,11 @@             },             {                 "cat": 4,-                "val": 20+                "val": 15             },             {                 "cat": 5,-                "val": 10+                "val": 12             }         ]     },
tests/specs/position/position7.vl view
@@ -21,11 +21,11 @@             },             {                 "cat": 4,-                "val": 20+                "val": 15             },             {                 "cat": 5,-                "val": 10+                "val": 12             }         ]     },
tests/specs/position/position8.vl view
@@ -17,11 +17,11 @@             },             {                 "cat": 4,-                "val": 20+                "val": 15             },             {                 "cat": 5,-                "val": 10+                "val": 12             }         ]     },
+ tests/specs/position/position8r.vl view
@@ -0,0 +1,45 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "empty": 0,+                "cat": 1,+                "val": 10+            },+            {+                "cat": 2,+                "val": 20+            },+            {+                "cat": 3,+                "val": 30+            },+            {+                "cat": 4,+                "val": 15+            },+            {+                "cat": 5,+                "val": 12+            }+        ]+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "scale": {+                "paddingInner": 0.5,+                "align": 0,+                "reverse": true+            },+            "type": "ordinal"+        },+        "y": {+            "field": "val",+            "type": "quantitative"+        }+    }+}
tests/specs/position/position9.vl view
@@ -17,11 +17,11 @@             },             {                 "cat": 4,-                "val": 20+                "val": 15             },             {                 "cat": 5,-                "val": 10+                "val": 12             }         ]     },
+ tests/specs/position/position9r.vl view
@@ -0,0 +1,45 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "empty": 0,+                "cat": 1,+                "val": 10+            },+            {+                "cat": 2,+                "val": 20+            },+            {+                "cat": 3,+                "val": 30+            },+            {+                "cat": 4,+                "val": 15+            },+            {+                "cat": 5,+                "val": 12+            }+        ]+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "scale": {+                "paddingInner": 0.5,+                "align": 0.3,+                "reverse": true+            },+            "type": "ordinal"+        },+        "y": {+            "field": "val",+            "type": "quantitative"+        }+    }+}
+ tests/specs/scale/diverging1.vl view
@@ -0,0 +1,66 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "category": "A",+                "value": -28.6+            },+            {+                "category": "B",+                "value": -1.6+            },+            {+                "category": "C",+                "value": -13.6+            },+            {+                "category": "D",+                "value": 34.4+            },+            {+                "category": "E",+                "value": 24.4+            },+            {+                "category": "F",+                "value": -3.6+            },+            {+                "category": "G",+                "value": -57.6+            },+            {+                "category": "H",+                "value": 30.4+            },+            {+                "category": "I",+                "value": -4.6+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "value",+            "scale": {+                "scheme": "redblue"+            },+            "type": "quantitative"+        },+        "x": {+            "field": "category",+            "type": "ordinal",+            "axis": {+                "labelAngle": 0,+                "domain": false,+                "orient": "top"+            }+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
+ tests/specs/scale/diverging2.vl view
@@ -0,0 +1,67 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "category": "A",+                "value": -28.6+            },+            {+                "category": "B",+                "value": -1.6+            },+            {+                "category": "C",+                "value": -13.6+            },+            {+                "category": "D",+                "value": 34.4+            },+            {+                "category": "E",+                "value": 24.4+            },+            {+                "category": "F",+                "value": -3.6+            },+            {+                "category": "G",+                "value": -57.6+            },+            {+                "category": "H",+                "value": 30.4+            },+            {+                "category": "I",+                "value": -4.6+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "value",+            "scale": {+                "scheme": "redblue",+                "domainMid": 0+            },+            "type": "quantitative"+        },+        "x": {+            "field": "category",+            "type": "ordinal",+            "axis": {+                "labelAngle": 0,+                "domain": false,+                "orient": "top"+            }+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
tests/specs/time/utcTime.vl view
@@ -48,7 +48,10 @@             "scale": {                 "type": "utc"             },-            "timeUnit": "utcyearmonthdatehours",+            "timeUnit": {+                "utc": true,+                "unit": "yearmonthdatehours"+            },             "type": "temporal",             "axis": {                 "format": "%d %b %H:%M"
tests/specs/viewcomposition/columns1.vl view
@@ -37,7 +37,8 @@         "column": {             "field": "gender",             "header": {},-            "type": "nominal"+            "type": "nominal",+            "spacing": 0         },         "y": {             "field": "people",
tests/specs/viewcomposition/columns2.vl view
@@ -40,7 +40,8 @@                 "labelFontSize": 15,                 "titleFontSize": 20             },-            "type": "nominal"+            "type": "nominal",+            "spacing": 0         },         "y": {             "field": "people",
tests/specs/viewcomposition/columns3.vl view
@@ -40,7 +40,8 @@         "column": {             "field": "gender",             "header": {},-            "type": "nominal"+            "type": "nominal",+            "spacing": 0         },         "y": {             "field": "people",
tests/specs/viewcomposition/columns4.vl view
@@ -42,7 +42,8 @@                 "labelFontSize": 15,                 "titleFontSize": 20             },-            "type": "nominal"+            "type": "nominal",+            "spacing": 0         },         "y": {             "field": "people",
tests/specs/viewcomposition/grid1.vl view
@@ -4,8 +4,11 @@             "labelFontSize": 0.1         },         "view": {+            "strokeWidth": 2,             "continuousHeight": 120,-            "stroke": null+            "stroke": "black",+            "fill": "gray",+            "fillOpacity": 0.2         },         "facet": {             "columns": 5,@@ -414,7 +417,7 @@         }     },     "spacing": {-        "row": 20,-        "column": 80+        "row": 10,+        "column": 30     } }
tests/specs/viewcomposition/grid2.vl view
@@ -10,8 +10,11 @@             "labelFontSize": 0.1         },         "view": {+            "strokeWidth": 2,             "continuousHeight": 120,-            "stroke": null+            "stroke": "black",+            "fill": "gray",+            "fillOpacity": 0.2         },         "facet": {             "columns": 5,
tests/specs/viewcomposition/grid3.vl view
@@ -10,8 +10,11 @@             "labelFontSize": 0.1         },         "view": {+            "strokeWidth": 2,             "continuousHeight": 120,-            "stroke": null+            "stroke": "black",+            "fill": "gray",+            "fillOpacity": 0.2         },         "facet": {             "spacing": 80@@ -404,7 +407,7 @@         }     },     "$schema": "https://vega.github.io/schema/vega-lite/v4.json",-    "columns": 5,+    "columns": 0,     "facet": {         "field": "index",         "header": {
+ tests/specs/viewcomposition/groupyage.vl view
@@ -0,0 +1,60 @@+{+    "transform": [+        {+            "filter": "datum.year == 2000"+        },+        {+            "as": "gender",+            "calculate": "datum.sex == 2 ? 'Female' : 'Male'"+        }+    ],+    "config": {+        "view": {+            "stroke": null+        },+        "axis": {+            "domainWidth": 1+        }+    },+    "mark": "bar",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "width": {+        "step": 12+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "gender",+            "scale": {+                "range": [+                    "#675193",+                    "#ca8861"+                ]+            },+            "type": "nominal"+        },+        "x": {+            "field": "gender",+            "type": "nominal",+            "axis": {+                "title": null+            }+        },+        "column": {+            "field": "age",+            "type": "ordinal",+            "spacing": 10+        },+        "y": {+            "field": "people",+            "aggregate": "sum",+            "type": "quantitative",+            "axis": {+                "grid": false,+                "title": "Population"+            }+        }+    }+}
tests/specs/windowtransform/window3.vl view
@@ -32,7 +32,7 @@         "url": "https://vega.github.io/vega-lite/data/movies.json",         "format": {             "parse": {-                "Release_Date": "date:'%d-%b-%y'"+                "Release_Date": "date:'%b %d %Y'"             }         }     },
tests/specs/windowtransform/window4.vl view
@@ -41,7 +41,7 @@         "url": "https://vega.github.io/vega-lite/data/movies.json",         "format": {             "parse": {-                "Release_Date": "date:'%d-%b-%y'"+                "Release_Date": "date:'%b %d %Y'"             }         }     },