diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -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),
diff --git a/hvega.cabal b/hvega.cabal
--- a/hvega.cabal
+++ b/hvega.cabal
@@ -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
diff --git a/hvega.nix b/hvega.nix
--- a/hvega.nix
+++ b/hvega.nix
@@ -3,7 +3,7 @@
 }:
 mkDerivation {
   pname = "hvega";
-  version = "0.5.0.0";
+  version = "0.6.0.0";
   src = ./.;
   isLibrary = true;
   isExecutable = true;
diff --git a/src/Graphics/Vega/Tutorials/VegaLite.hs b/src/Graphics/Vega/Tutorials/VegaLite.hs
--- a/src/Graphics/Vega/Tutorials/VegaLite.hs
+++ b/src/Graphics/Vega/Tutorials/VegaLite.hs
@@ -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
diff --git a/src/Graphics/Vega/VegaLite.hs b/src/Graphics/Vega/VegaLite.hs
--- a/src/Graphics/Vega/VegaLite.hs
+++ b/src/Graphics/Vega/VegaLite.hs
@@ -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'
diff --git a/src/Graphics/Vega/VegaLite/Configuration.hs b/src/Graphics/Vega/VegaLite/Configuration.hs
--- a/src/Graphics/Vega/VegaLite/Configuration.hs
+++ b/src/Graphics/Vega/VegaLite/Configuration.hs
@@ -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
 
 
 {-|
diff --git a/src/Graphics/Vega/VegaLite/Core.hs b/src/Graphics/Vega/VegaLite/Core.hs
--- a/src/Graphics/Vega/VegaLite/Core.hs
+++ b/src/Graphics/Vega/VegaLite/Core.hs
@@ -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
diff --git a/src/Graphics/Vega/VegaLite/Foundation.hs b/src/Graphics/Vega/VegaLite/Foundation.hs
--- a/src/Graphics/Vega/VegaLite/Foundation.hs
+++ b/src/Graphics/Vega/VegaLite/Foundation.hs
@@ -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
diff --git a/src/Graphics/Vega/VegaLite/Mark.hs b/src/Graphics/Vega/VegaLite/Mark.hs
--- a/src/Graphics/Vega/VegaLite/Mark.hs
+++ b/src/Graphics/Vega/VegaLite/Mark.hs
@@ -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
diff --git a/src/Graphics/Vega/VegaLite/Scale.hs b/src/Graphics/Vega/VegaLite/Scale.hs
--- a/src/Graphics/Vega/VegaLite/Scale.hs
+++ b/src/Graphics/Vega/VegaLite/Scale.hs
@@ -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
+
+-}
diff --git a/src/Graphics/Vega/VegaLite/Selection.hs b/src/Graphics/Vega/VegaLite/Selection.hs
--- a/src/Graphics/Vega/VegaLite/Selection.hs
+++ b/src/Graphics/Vega/VegaLite/Selection.hs
@@ -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
diff --git a/src/Graphics/Vega/VegaLite/Time.hs b/src/Graphics/Vega/VegaLite/Time.hs
--- a/src/Graphics/Vega/VegaLite/Time.hs
+++ b/src/Graphics/Vega/VegaLite/Time.hs
@@ -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
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -5,4 +5,4 @@
 
 extra-deps: []
 
-resolver: lts-14.23
+resolver: lts-15.0
diff --git a/tests/AxisTests.hs b/tests/AxisTests.hs
--- a/tests/AxisTests.hs
+++ b/tests/AxisTests.hs
@@ -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 []
+                ]
diff --git a/tests/CompositeTests.hs b/tests/CompositeTests.hs
--- a/tests/CompositeTests.hs
+++ b/tests/CompositeTests.hs
@@ -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
diff --git a/tests/ConditionalTests.hs b/tests/ConditionalTests.hs
--- a/tests/ConditionalTests.hs
+++ b/tests/ConditionalTests.hs
@@ -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 [] ]
diff --git a/tests/ConfigTests.hs b/tests/ConfigTests.hs
--- a/tests/ConfigTests.hs
+++ b/tests/ConfigTests.hs
@@ -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)
 
 
diff --git a/tests/DataTests.hs b/tests/DataTests.hs
--- a/tests/DataTests.hs
+++ b/tests/DataTests.hs
@@ -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]))]
 
 
 {-
diff --git a/tests/EncodingTests.hs b/tests/EncodingTests.hs
new file mode 100644
--- /dev/null
+++ b/tests/EncodingTests.hs
@@ -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 ]
+               $ []
+             ]
diff --git a/tests/FillStrokeTests.hs b/tests/FillStrokeTests.hs
--- a/tests/FillStrokeTests.hs
+++ b/tests/FillStrokeTests.hs
@@ -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
diff --git a/tests/Gallery/Advanced.hs b/tests/Gallery/Advanced.hs
--- a/tests/Gallery/Advanced.hs
+++ b/tests/Gallery/Advanced.hs
@@ -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 ] )
                         ]
diff --git a/tests/Gallery/Area.hs b/tests/Gallery/Area.hs
--- a/tests/Gallery/Area.hs
+++ b/tests/Gallery/Area.hs
@@ -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
diff --git a/tests/Gallery/Bar.hs b/tests/Gallery/Bar.hs
--- a/tests/Gallery/Bar.hs
+++ b/tests/Gallery/Bar.hs
@@ -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 []
diff --git a/tests/Gallery/Facet.hs b/tests/Gallery/Facet.hs
--- a/tests/Gallery/Facet.hs
+++ b/tests/Gallery/Facet.hs
@@ -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 [] ]
diff --git a/tests/Gallery/Geo.hs b/tests/Gallery/Geo.hs
--- a/tests/Gallery/Geo.hs
+++ b/tests/Gallery/Geo.hs
@@ -30,7 +30,7 @@
 cfg :: [ConfigureSpec] -> PropertySpec
 cfg =
     configure
-        . configuration (View [ ViewStroke Nothing ])
+        . configuration (ViewStyle [ ViewNoStroke ])
 
 
 geo1 :: VegaLite
diff --git a/tests/Gallery/Interaction.hs b/tests/Gallery/Interaction.hs
--- a/tests/Gallery/Interaction.hs
+++ b/tests/Gallery/Interaction.hs
@@ -42,7 +42,7 @@
 
         config =
             configure
-                . configuration (Scale [ SCBandPaddingInner 0.2 ])
+                . configuration (ScaleStyle [ SCBandPaddingInner 0.2 ])
 
         dvals =
             dataFromColumns []
diff --git a/tests/Gallery/Label.hs b/tests/Gallery/Label.hs
--- a/tests/Gallery/Label.hs
+++ b/tests/Gallery/Label.hs
@@ -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
+                ]
diff --git a/tests/Gallery/Layer.hs b/tests/Gallery/Layer.hs
--- a/tests/Gallery/Layer.hs
+++ b/tests/Gallery/Layer.hs
@@ -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
diff --git a/tests/Gallery/Line.hs b/tests/Gallery/Line.hs
--- a/tests/Gallery/Line.hs
+++ b/tests/Gallery/Line.hs
@@ -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
diff --git a/tests/Gallery/Multi.hs b/tests/Gallery/Multi.hs
--- a/tests/Gallery/Multi.hs
+++ b/tests/Gallery/Multi.hs
@@ -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
diff --git a/tests/Gallery/Repeat.hs b/tests/Gallery/Repeat.hs
--- a/tests/Gallery/Repeat.hs
+++ b/tests/Gallery/Repeat.hs
@@ -176,8 +176,8 @@
 
         config =
             configure
-                . configuration (Range [ RHeatmap "greenblue" ])
-                . configuration (View [ ViewStroke Nothing ])
+                . configuration (RangeStyle [ RHeatmap "greenblue" ])
+                . configuration (ViewStyle [ ViewNoStroke ])
 
         enc1 =
             encoding
diff --git a/tests/Gallery/Table.hs b/tests/Gallery/Table.hs
--- a/tests/Gallery/Table.hs
+++ b/tests/Gallery/Table.hs
@@ -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
diff --git a/tests/GeoTests.hs b/tests/GeoTests.hs
--- a/tests/GeoTests.hs
+++ b/tests/GeoTests.hs
@@ -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
diff --git a/tests/InteractionTests.hs b/tests/InteractionTests.hs
--- a/tests/InteractionTests.hs
+++ b/tests/InteractionTests.hs
@@ -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
diff --git a/tests/LegendTests.hs b/tests/LegendTests.hs
--- a/tests/LegendTests.hs
+++ b/tests/LegendTests.hs
@@ -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]
+                ]
diff --git a/tests/PositionTests.hs b/tests/PositionTests.hs
--- a/tests/PositionTests.hs
+++ b/tests/PositionTests.hs
@@ -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
diff --git a/tests/ProjectionTests.hs b/tests/ProjectionTests.hs
--- a/tests/ProjectionTests.hs
+++ b/tests/ProjectionTests.hs
@@ -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
diff --git a/tests/ScaleTests.hs b/tests/ScaleTests.hs
--- a/tests/ScaleTests.hs
+++ b/tests/ScaleTests.hs
@@ -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 []
+                        ]
diff --git a/tests/ShapeTests.hs b/tests/ShapeTests.hs
--- a/tests/ShapeTests.hs
+++ b/tests/ShapeTests.hs
@@ -257,7 +257,7 @@
     let
         config =
             configure
-                . configuration (View [ ViewStroke Nothing ])
+                . configuration (ViewStyle [ ViewNoStroke ])
 
         dataVals =
             dataFromColumns []
diff --git a/tests/Test.hs b/tests/Test.hs
--- a/tests/Test.hs
+++ b/tests/Test.hs
@@ -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
   ]
diff --git a/tests/TransformTests.hs b/tests/TransformTests.hs
new file mode 100644
--- /dev/null
+++ b/tests/TransformTests.hs
@@ -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 []
+        ]
diff --git a/tests/ViewCompositionTests.hs b/tests/ViewCompositionTests.hs
--- a/tests/ViewCompositionTests.hs
+++ b/tests/ViewCompositionTests.hs
@@ -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
                ]
              ]
 
diff --git a/tests/WindowTransformTests.hs b/tests/WindowTransformTests.hs
--- a/tests/WindowTransformTests.hs
+++ b/tests/WindowTransformTests.hs
@@ -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
diff --git a/tests/specs/axis/axis1c.vl b/tests/specs/axis/axis1c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis1c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axis2c.vl b/tests/specs/axis/axis2c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis2c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axis3c.vl b/tests/specs/axis/axis3c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis3c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axis4c.vl b/tests/specs/axis/axis4c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis4c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axis5c.vl b/tests/specs/axis/axis5c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis5c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axis6c.vl b/tests/specs/axis/axis6c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis6c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axis7c.vl b/tests/specs/axis/axis7c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis7c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axis8c.vl b/tests/specs/axis/axis8c.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axis8c.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axisstyleempty.vl b/tests/specs/axis/axisstyleempty.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axisstyleempty.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axisstyleemptyx.vl b/tests/specs/axis/axisstyleemptyx.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axisstyleemptyx.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axisstylex.vl b/tests/specs/axis/axisstylex.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axisstylex.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/axis/axisstylexy.vl b/tests/specs/axis/axisstylexy.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axisstylexy.vl
@@ -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"
+            }
+        }
+    }
+}
diff --git a/tests/specs/composite/boxplotnobox.vl b/tests/specs/composite/boxplotnobox.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/boxplotnobox.vl
@@ -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"
+            }
+        }
+    }
+}
diff --git a/tests/specs/composite/boxplotnomedian.vl b/tests/specs/composite/boxplotnomedian.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/boxplotnomedian.vl
@@ -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"
+            }
+        }
+    }
+}
diff --git a/tests/specs/composite/boxplotnooutliers.vl b/tests/specs/composite/boxplotnooutliers.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/boxplotnooutliers.vl
@@ -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"
+            }
+        }
+    }
+}
diff --git a/tests/specs/composite/boxplotnorule.vl b/tests/specs/composite/boxplotnorule.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/boxplotnorule.vl
@@ -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"
+            }
+        }
+    }
+}
diff --git a/tests/specs/composite/boxplotnoticks.vl b/tests/specs/composite/boxplotnoticks.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/boxplotnoticks.vl
@@ -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"
+            }
+        }
+    }
+}
diff --git a/tests/specs/composite/errorband1.vl b/tests/specs/composite/errorband1.vl
--- a/tests/specs/composite/errorband1.vl
+++ b/tests/specs/composite/errorband1.vl
@@ -1,6 +1,6 @@
 {
     "mark": {
-        "borders": {},
+        "borders": true,
         "extent": "ci",
         "interpolate": "monotone",
         "type": "errorband"
diff --git a/tests/specs/composite/errorband1no.vl b/tests/specs/composite/errorband1no.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/errorband1no.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/composite/errorband2.vl b/tests/specs/composite/errorband2.vl
--- a/tests/specs/composite/errorband2.vl
+++ b/tests/specs/composite/errorband2.vl
@@ -1,6 +1,6 @@
 {
     "mark": {
-        "borders": {},
+        "borders": true,
         "extent": "stdev",
         "interpolate": "monotone",
         "type": "errorband"
diff --git a/tests/specs/composite/errorband2no.vl b/tests/specs/composite/errorband2no.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/errorband2no.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/composite/errorbar3.vl b/tests/specs/composite/errorbar3.vl
--- a/tests/specs/composite/errorbar3.vl
+++ b/tests/specs/composite/errorbar3.vl
@@ -7,7 +7,7 @@
         {
             "mark": {
                 "type": "errorbar",
-                "ticks": {}
+                "ticks": true
             },
             "encoding": {
                 "color": {
diff --git a/tests/specs/composite/errorbar3no.vl b/tests/specs/composite/errorbar3no.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/composite/errorbar3no.vl
@@ -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"
+}
diff --git a/tests/specs/composite/errorbar4.vl b/tests/specs/composite/errorbar4.vl
--- a/tests/specs/composite/errorbar4.vl
+++ b/tests/specs/composite/errorbar4.vl
@@ -32,7 +32,7 @@
         {
             "mark": {
                 "type": "errorbar",
-                "ticks": {}
+                "ticks": true
             },
             "encoding": {
                 "x": {
diff --git a/tests/specs/composite/errorbar5.vl b/tests/specs/composite/errorbar5.vl
--- a/tests/specs/composite/errorbar5.vl
+++ b/tests/specs/composite/errorbar5.vl
@@ -32,7 +32,7 @@
         {
             "mark": {
                 "type": "errorbar",
-                "ticks": {}
+                "ticks": true
             },
             "encoding": {
                 "xError2": {
diff --git a/tests/specs/composite/errorbar6.vl b/tests/specs/composite/errorbar6.vl
--- a/tests/specs/composite/errorbar6.vl
+++ b/tests/specs/composite/errorbar6.vl
@@ -32,7 +32,7 @@
         {
             "mark": {
                 "type": "errorbar",
-                "ticks": {}
+                "ticks": true
             },
             "encoding": {
                 "yError": {
diff --git a/tests/specs/composite/errorbar7.vl b/tests/specs/composite/errorbar7.vl
--- a/tests/specs/composite/errorbar7.vl
+++ b/tests/specs/composite/errorbar7.vl
@@ -32,7 +32,7 @@
         {
             "mark": {
                 "type": "errorbar",
-                "ticks": {}
+                "ticks": true
             },
             "encoding": {
                 "yError2": {
diff --git a/tests/specs/conditional/axisCondition2.vl b/tests/specs/conditional/axisCondition2.vl
--- a/tests/specs/conditional/axisCondition2.vl
+++ b/tests/specs/conditional/axisCondition2.vl
@@ -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": {
diff --git a/tests/specs/conditional/axisDateCondition1.vl b/tests/specs/conditional/axisDateCondition1.vl
--- a/tests/specs/conditional/axisDateCondition1.vl
+++ b/tests/specs/conditional/axisDateCondition1.vl
@@ -1,6 +1,6 @@
 {
     "mark": {
-        "borders": {},
+        "borders": true,
         "extent": "iqr",
         "interpolate": "monotone",
         "type": "errorband"
diff --git a/tests/specs/conditional/axisconditionlabeloffset.vl b/tests/specs/conditional/axisconditionlabeloffset.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/conditional/axisconditionlabeloffset.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/config/fontCfg.vl b/tests/specs/config/fontCfg.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/config/fontCfg.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/data/domain1.vl b/tests/specs/data/domain1.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/data/domain1.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/data/domain2.vl b/tests/specs/data/domain2.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/data/domain2.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/data/domain3.vl b/tests/specs/data/domain3.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/data/domain3.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/hrounded.vl b/tests/specs/fillstroke/hrounded.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/hrounded.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/strokedash1.vl b/tests/specs/fillstroke/strokedash1.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash1.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/strokedash2.vl b/tests/specs/fillstroke/strokedash2.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash2.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/strokedash3.vl b/tests/specs/fillstroke/strokedash3.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash3.vl
@@ -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"
+}
diff --git a/tests/specs/fillstroke/strokedash4.vl b/tests/specs/fillstroke/strokedash4.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash4.vl
@@ -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"
+}
diff --git a/tests/specs/fillstroke/strokedash5.vl b/tests/specs/fillstroke/strokedash5.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash5.vl
@@ -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
+            }
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/strokedash6.vl b/tests/specs/fillstroke/strokedash6.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash6.vl
@@ -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
+            }
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/strokedash7.vl b/tests/specs/fillstroke/strokedash7.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash7.vl
@@ -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
+            }
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/strokedash8.vl b/tests/specs/fillstroke/strokedash8.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash8.vl
@@ -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
+            }
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/strokedash9.vl b/tests/specs/fillstroke/strokedash9.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/strokedash9.vl
@@ -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
+            }
+        }
+    }
+}
diff --git a/tests/specs/fillstroke/vrounded.vl b/tests/specs/fillstroke/vrounded.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/fillstroke/vrounded.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/gallery/facet/facet7.vl b/tests/specs/gallery/facet/facet7.vl
--- a/tests/specs/gallery/facet/facet7.vl
+++ b/tests/specs/gallery/facet/facet7.vl
@@ -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"
diff --git a/tests/specs/gallery/label/baselines.vl b/tests/specs/gallery/label/baselines.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/label/baselines.vl
@@ -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
+}
diff --git a/tests/specs/gallery/label/label2.vl b/tests/specs/gallery/label/label2.vl
--- a/tests/specs/gallery/label/label2.vl
+++ b/tests/specs/gallery/label/label2.vl
@@ -4,6 +4,7 @@
             "baseline": "middle"
         },
         "scale": {
+            "xReverse": false,
             "bandPaddingInner": 0,
             "bandPaddingOuter": 0
         }
diff --git a/tests/specs/gallery/label/label2r.vl b/tests/specs/gallery/label/label2r.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/label/label2r.vl
@@ -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'"
+}
diff --git a/tests/specs/gallery/label/label3.vl b/tests/specs/gallery/label/label3.vl
--- a/tests/specs/gallery/label/label3.vl
+++ b/tests/specs/gallery/label/label3.vl
@@ -149,7 +149,7 @@
             },
             "type": "quantitative",
             "axis": {
-                "title": "CO2 concentration in ppm"
+                "title": "CO₂ concentration in ppm"
             }
         }
     },
diff --git a/tests/specs/gallery/label/label8.vl b/tests/specs/gallery/label/label8.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/label/label8.vl
@@ -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"
+            }
+        ]
+    }
+}
diff --git a/tests/specs/gallery/label/label9.vl b/tests/specs/gallery/label/label9.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/label/label9.vl
@@ -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
+}
diff --git a/tests/specs/gallery/label/voyager.vl b/tests/specs/gallery/label/voyager.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/label/voyager.vl
@@ -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
+}
diff --git a/tests/specs/gallery/layer/layer6.vl b/tests/specs/gallery/layer/layer6.vl
--- a/tests/specs/gallery/layer/layer6.vl
+++ b/tests/specs/gallery/layer/layer6.vl
@@ -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"
 }
diff --git a/tests/specs/gallery/multi/multi4.vl b/tests/specs/gallery/multi/multi4.vl
--- a/tests/specs/gallery/multi/multi4.vl
+++ b/tests/specs/gallery/multi/multi4.vl
@@ -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": [
diff --git a/tests/specs/geo/mapComp3.vl b/tests/specs/geo/mapComp3.vl
--- a/tests/specs/geo/mapComp3.vl
+++ b/tests/specs/geo/mapComp3.vl
@@ -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
                         ]
diff --git a/tests/specs/geo/mapComp4.vl b/tests/specs/geo/mapComp4.vl
--- a/tests/specs/geo/mapComp4.vl
+++ b/tests/specs/geo/mapComp4.vl
@@ -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": [
diff --git a/tests/specs/interaction/curhelp.vl b/tests/specs/interaction/curhelp.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/interaction/curhelp.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/interaction/curpointer.vl b/tests/specs/interaction/curpointer.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/interaction/curpointer.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/legend/limits1.vl b/tests/specs/legend/limits1.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/legend/limits1.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/legend/limits2.vl b/tests/specs/legend/limits2.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/legend/limits2.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/legend/limits3.vl b/tests/specs/legend/limits3.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/legend/limits3.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/position/position10.vl b/tests/specs/position/position10.vl
--- a/tests/specs/position/position10.vl
+++ b/tests/specs/position/position10.vl
@@ -17,11 +17,11 @@
             },
             {
                 "cat": 4,
-                "val": 20
+                "val": 15
             },
             {
                 "cat": 5,
-                "val": 10
+                "val": 12
             }
         ]
     },
diff --git a/tests/specs/position/position10r.vl b/tests/specs/position/position10r.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/position/position10r.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/position/position11.vl b/tests/specs/position/position11.vl
--- a/tests/specs/position/position11.vl
+++ b/tests/specs/position/position11.vl
@@ -17,11 +17,11 @@
             },
             {
                 "cat": 4,
-                "val": 20
+                "val": 15
             },
             {
                 "cat": 5,
-                "val": 10
+                "val": 12
             }
         ]
     },
diff --git a/tests/specs/position/position11r.vl b/tests/specs/position/position11r.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/position/position11r.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/position/position12.vl b/tests/specs/position/position12.vl
--- a/tests/specs/position/position12.vl
+++ b/tests/specs/position/position12.vl
@@ -17,11 +17,11 @@
             },
             {
                 "cat": 4,
-                "val": 20
+                "val": 15
             },
             {
                 "cat": 5,
-                "val": 10
+                "val": 12
             }
         ]
     },
diff --git a/tests/specs/position/position12r.vl b/tests/specs/position/position12r.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/position/position12r.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/position/position6.vl b/tests/specs/position/position6.vl
--- a/tests/specs/position/position6.vl
+++ b/tests/specs/position/position6.vl
@@ -20,11 +20,11 @@
             },
             {
                 "cat": 4,
-                "val": 20
+                "val": 15
             },
             {
                 "cat": 5,
-                "val": 10
+                "val": 12
             }
         ]
     },
diff --git a/tests/specs/position/position7.vl b/tests/specs/position/position7.vl
--- a/tests/specs/position/position7.vl
+++ b/tests/specs/position/position7.vl
@@ -21,11 +21,11 @@
             },
             {
                 "cat": 4,
-                "val": 20
+                "val": 15
             },
             {
                 "cat": 5,
-                "val": 10
+                "val": 12
             }
         ]
     },
diff --git a/tests/specs/position/position8.vl b/tests/specs/position/position8.vl
--- a/tests/specs/position/position8.vl
+++ b/tests/specs/position/position8.vl
@@ -17,11 +17,11 @@
             },
             {
                 "cat": 4,
-                "val": 20
+                "val": 15
             },
             {
                 "cat": 5,
-                "val": 10
+                "val": 12
             }
         ]
     },
diff --git a/tests/specs/position/position8r.vl b/tests/specs/position/position8r.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/position/position8r.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/position/position9.vl b/tests/specs/position/position9.vl
--- a/tests/specs/position/position9.vl
+++ b/tests/specs/position/position9.vl
@@ -17,11 +17,11 @@
             },
             {
                 "cat": 4,
-                "val": 20
+                "val": 15
             },
             {
                 "cat": 5,
-                "val": 10
+                "val": 12
             }
         ]
     },
diff --git a/tests/specs/position/position9r.vl b/tests/specs/position/position9r.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/position/position9r.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/scale/diverging1.vl b/tests/specs/scale/diverging1.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/scale/diverging1.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/scale/diverging2.vl b/tests/specs/scale/diverging2.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/scale/diverging2.vl
@@ -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"
+        }
+    }
+}
diff --git a/tests/specs/time/utcTime.vl b/tests/specs/time/utcTime.vl
--- a/tests/specs/time/utcTime.vl
+++ b/tests/specs/time/utcTime.vl
@@ -48,7 +48,10 @@
             "scale": {
                 "type": "utc"
             },
-            "timeUnit": "utcyearmonthdatehours",
+            "timeUnit": {
+                "utc": true,
+                "unit": "yearmonthdatehours"
+            },
             "type": "temporal",
             "axis": {
                 "format": "%d %b %H:%M"
diff --git a/tests/specs/viewcomposition/columns1.vl b/tests/specs/viewcomposition/columns1.vl
--- a/tests/specs/viewcomposition/columns1.vl
+++ b/tests/specs/viewcomposition/columns1.vl
@@ -37,7 +37,8 @@
         "column": {
             "field": "gender",
             "header": {},
-            "type": "nominal"
+            "type": "nominal",
+            "spacing": 0
         },
         "y": {
             "field": "people",
diff --git a/tests/specs/viewcomposition/columns2.vl b/tests/specs/viewcomposition/columns2.vl
--- a/tests/specs/viewcomposition/columns2.vl
+++ b/tests/specs/viewcomposition/columns2.vl
@@ -40,7 +40,8 @@
                 "labelFontSize": 15,
                 "titleFontSize": 20
             },
-            "type": "nominal"
+            "type": "nominal",
+            "spacing": 0
         },
         "y": {
             "field": "people",
diff --git a/tests/specs/viewcomposition/columns3.vl b/tests/specs/viewcomposition/columns3.vl
--- a/tests/specs/viewcomposition/columns3.vl
+++ b/tests/specs/viewcomposition/columns3.vl
@@ -40,7 +40,8 @@
         "column": {
             "field": "gender",
             "header": {},
-            "type": "nominal"
+            "type": "nominal",
+            "spacing": 0
         },
         "y": {
             "field": "people",
diff --git a/tests/specs/viewcomposition/columns4.vl b/tests/specs/viewcomposition/columns4.vl
--- a/tests/specs/viewcomposition/columns4.vl
+++ b/tests/specs/viewcomposition/columns4.vl
@@ -42,7 +42,8 @@
                 "labelFontSize": 15,
                 "titleFontSize": 20
             },
-            "type": "nominal"
+            "type": "nominal",
+            "spacing": 0
         },
         "y": {
             "field": "people",
diff --git a/tests/specs/viewcomposition/grid1.vl b/tests/specs/viewcomposition/grid1.vl
--- a/tests/specs/viewcomposition/grid1.vl
+++ b/tests/specs/viewcomposition/grid1.vl
@@ -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
     }
 }
diff --git a/tests/specs/viewcomposition/grid2.vl b/tests/specs/viewcomposition/grid2.vl
--- a/tests/specs/viewcomposition/grid2.vl
+++ b/tests/specs/viewcomposition/grid2.vl
@@ -10,8 +10,11 @@
             "labelFontSize": 0.1
         },
         "view": {
+            "strokeWidth": 2,
             "continuousHeight": 120,
-            "stroke": null
+            "stroke": "black",
+            "fill": "gray",
+            "fillOpacity": 0.2
         },
         "facet": {
             "columns": 5,
diff --git a/tests/specs/viewcomposition/grid3.vl b/tests/specs/viewcomposition/grid3.vl
--- a/tests/specs/viewcomposition/grid3.vl
+++ b/tests/specs/viewcomposition/grid3.vl
@@ -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": {
diff --git a/tests/specs/viewcomposition/groupyage.vl b/tests/specs/viewcomposition/groupyage.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/viewcomposition/groupyage.vl
@@ -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"
+            }
+        }
+    }
+}
diff --git a/tests/specs/windowtransform/window3.vl b/tests/specs/windowtransform/window3.vl
--- a/tests/specs/windowtransform/window3.vl
+++ b/tests/specs/windowtransform/window3.vl
@@ -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'"
             }
         }
     },
diff --git a/tests/specs/windowtransform/window4.vl b/tests/specs/windowtransform/window4.vl
--- a/tests/specs/windowtransform/window4.vl
+++ b/tests/specs/windowtransform/window4.vl
@@ -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'"
             }
         }
     },
