diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,54 @@
 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.7.0.0
+
+The Vega-Lite tests are now validated against version 4.7 of the
+Vega-Lite schema.
+
+### New functionality
+
+The `BlendMode` type has been added for controlling how marks blend
+with their background. This is used with the new `MBlend` constructor
+for marks.
+
+### Breaking Change
+
+The axis style options for specific data- or mark- types (`AxisBand`,
+`AxisDiscrete`, `AxisPoint`, `AxisQuantitative`, and `AxisTemporal`)
+have been changed to accept an additional argument (the new
+`AxisChoice` type) which defines which axis (X, Y, or both) the
+configuration should be applied to. This is to support new axis
+configuration options added in Vega-Lite 4.7.0.
+
+The `ChTooltip` `Channel` constructor has been removed as support
+for this channel type was dropped in Vega-Lite 4.
+
+### New constructors
+
+The `ScaleDomain` type has gained `DSelectionField` and
+`DSelectionChannel` constructors, which allow you to link a scale
+(e.g. an axis) to a selection that is projected over multiple fields
+or encodings.
+
+The `Operation` type has gained the `Product` specifier from Vega-Lite
+4.6.0.
+
+The `TextChannel` has gained `TStrings` to support multi-line labels.
+
+The `VAlign` type has gained `AlignLineTop` and `AlignLineBottom`
+(Vega-Lite 4.6.0).
+
+`LineBreakStyle` has been added to `ConfigurationProperty`.
+
+The height of multi-line axis labels can now be set with the
+`LabelLineHeight` and `AxLabelLineHeight` properties of the
+`AxisConfig` and `AxisProperty` types (Vega-Lite 4.6.0).
+
+Numeric filter ranges, specified with `FRange`, can now be lower- or
+upper-limits - `NumberRange` and `NumberRange` respectively - added to
+the `FilterRange` type.
+
 ## 0.6.0.0
 
 The Vega-Lite tests are now validated against version 4.5 of the
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
 # hvega
 
-[![vega-lite version](https://img.shields.io/badge/Vega--Lite-v4.5-purple.svg)](https://vega.github.io/vega-lite/)
+[![vega-lite version](https://img.shields.io/badge/Vega--Lite-v4.7-purple.svg)](https://vega.github.io/vega-lite/)
 
 Create [Vega-Lite](https://vega.github.io/vega-lite/) visualizations in
-Haskell. It targets version 4.5 of the Vega-Lite specification. Note that
+Haskell. It targets version 4.7 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),
@@ -22,8 +22,17 @@
 
 This code is released under the BSD3 license.
 
-## Example
+## Examples
 
+### Cars
+
+The [Vega-Lite example gallery](https://vega.github.io/vega-lite/examples/) contain
+a number of visualizations of the `cars.json` dataset, which has a number of
+columns to display, such as "Horsepower", "Miles_per_Gallon", and "Origin". The
+following code will create a visualization that plots the efficiency of the
+cars (the "mpg") as a function of its Horsepower, and color-code by the
+origin of the car:
+
 ```Haskell
 let cars =  dataFromUrl "https://vega.github.io/vega-datasets/data/cars.json" []
 
@@ -37,10 +46,118 @@
 in toVegaLite [ bkg, cars, mark Circle [], enc [] ]
 ```
 
-When viewed with a Vega-Lite aware viewer, the resultant plot is
+When the JSON is viewed with a Vega-Lite aware viewer, the resultant plot is
 
 ![Simple scatterplot](https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/images/intro.png "Simple scatterplot")
 
+### Betelgeuse
+
+In late 2019 and early 2020 the
+[star Betelgeuse](https://en.wikipedia.org/wiki/Betelgeuse) - a member of the
+[constellation Orion](https://en.wikipedia.org/wiki/Orion_(constellation)) -
+dimmed enough that you could see it. Betelgeuse is a member of the class of
+Red Supergiant stars, which are massive enough that they will go supernova
+at some point, and so there was
+[some speculation](https://en.wikipedia.org/wiki/Betelgeuse#2019%E2%80%932020_fading)
+that we could see a "naked-eye" supernova (even though the current models
+suggest that Betelgeuse has about 100,000 more years to go before this happens).
+This interest lead to a lot of observations added to the
+[American Association of Variable Star Observers](https://www.aavso.org/)
+database, which we are going to look at below. This example is rather-more
+involved than the case one, since it involves data filtering and creation,
+multiple plots, faceting, and interactive selection.
+
+```Haskell
+let titleStr = "Betelegeuse's magnitude measurements, collated by AAVSO"
+
+    w = width 600
+    h = height 150
+
+    pos1Opts fld ttl = [PName fld, PmType Quantitative, PAxis [AxTitle ttl]]
+    x1Opts = pos1Opts "days" "Days since January 1, 2020"
+    y1Opts = pos1Opts "magnitude" "Magnitude" ++ [PSort [Descending], yRange]
+    yRange = PScale [SDomain (DNumbers [-1, 3])]
+
+    filtOpts = [MName "filterName", MmType Nominal]
+    filtEnc = color (MLegend [ LTitle "Filter", LTitleFontSize 16, LLabelFontSize 14 ] : filtOpts)
+              . shape filtOpts
+
+    circle = mark Point [ MOpacity 0.5, MFilled False ]
+
+    encOverview = encoding
+                  . position X x1Opts
+                  . position Y y1Opts
+                  . filtEnc
+
+    selName = "brush"
+    pos2Opts fld = [PName fld, PmType Quantitative, PAxis [AxNoTitle],
+                   PScale [SDomain (DSelectionField selName fld)]]
+    x2Opts = pos2Opts "days"
+    y2Opts = pos2Opts "magnitude" ++ [PSort [Descending]]
+
+    encDetail = encoding
+                . position X x2Opts
+                . position Y y2Opts
+                . filtEnc
+
+    xlim = (Number (-220), Number 100)
+    ylim = (Number (-0.5), Number 2.5)
+    overview = asSpec [ w
+                      , h
+                      , encOverview []
+                      , selection
+                        . select selName Interval [ Encodings [ChX, ChY]
+                                                  , SInitInterval (Just xlim) (Just ylim)
+                                                  ]
+                        $ []
+                      , circle
+                      ]
+
+    detailPlot = asSpec [ w
+                        , h
+                        , encDetail []
+                        , circle
+                        ]
+
+    headerOpts = [ HLabelFontSize 16
+                 , HLabelAlign AlignRight
+                 , HLabelAnchor AEnd
+                 , HLabelPadding (-24)
+                 , HNoTitle
+                 , HLabelExpr "'Filter: ' + datum.label"
+                 ]
+
+    details = asSpec [ columns 1
+                     , facetFlow [ FName "filterName"
+                                 , FmType Nominal
+                                 , FHeader headerOpts
+                                 ]
+                     , spacing 10
+                     , specification detailPlot
+                     ]
+
+in toVegaLite [ title titleStr [ TFontSize 18 ]
+              , dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/betelgeuse-2020-03-19.json" []
+              , transform
+                . filter (FExpr "datum.filterName[0] === 'V'")
+                . filter (FExpr "datum.magnitude < 4")
+                . calculateAs "datum.jd - 2458849.0" "days"
+                $ []
+              , vConcat [overview, details]
+              , configure
+                . configuration (Axis [ TitleFontWeight Normal, TitleFontSize 16, LabelFontSize 14 ])
+                $ []
+              ]
+```
+
+This can be viewed as
+
+ - an [interactive version](https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxhJUBLAG2gFNY8oATeaAVywDpKb6A5eFloEADAF0wAXmlgA5ADVZkAL4AaYhDI86DfJBbsuWeAHNEFdk1pgAPGAAsK9SVKR4yRvvgBPD6qgAxvBUAWxUrLSeBhycAFZMYAC0YABM9gCsAByZ9gCcnCIqxGLOgeiIlCaMoC5uAB4UHvg1LlDQFlS0AGLl0ADqtBQmABbQnoiYxlSQpbXhAEa0VD2I0ADKFABekfgAjPazJDAd3b0b24y7AGwaYMrEasRe0PDVt5BssNN6o9AADshcAB6IEIADunBMFmGbHmbGQ9ACvVoq04SKwQIAIug2CYAEKfADWtCBwwAbrQTPAgcZkDpSRSqUCDNTFnQqCZaPDaIkUiI+YkRABmRK7fKxZDlSAPUqQMlIxBBMb4IguFq1YaDEbKsC7dIiQ4QSDGWCE6qQdB-eABCzeRgiTjpfwwbx-HZQP7oCirGZQHidJiMVDBBGPVpQMEUJjQYaMK4iA23I0IzoBdpS5pJo7zWDw2OZ8O1b0Wc11RgEXl8-y7BMlKB2lWCx3+FKOsRhwtGlFIpjekxNQiQMvOu0lLO1aCu92Qb06MnBaWd+7hju1bvoXuIKoFwuQJFUTBvTtGyhLQN6bT8QSRQ2tF1u8boLDehe3uaUlHn0jju8LJYrdYtndfY3zvdpoE6TwumoHQZh-CcTgA85gJuY87h-Vc72QYZ4AfZpyAoM9PEvWABCEX172nCZn0QBdMNqMsd07AiiL0FhfDgtDKM8ABHNgkHA1gKApTjj3qRpzXAyC9ExHxkDAZBvQCawACkkH42BvF1Ft+UKZdC3oo4G2-LjTyoL9jVMcxLBveCoGQIJpNcJgn3gb1y1FfwhXbUDk0wHV9FoBzPz7UTmMnPCoD4gSLCEkTfKgeAGgHMgpOnABZKyLDYKwiiXLN9IgTD1SOZA3QCI9d01IZRkufVQMs01zUta1bXtZs2inTxPVnCj-VoL9gyoUMGsjaN8zAeNE2Y9dN23EyxP3Q8mLEsyLJIsjbLQo0Iqop8X2mBKjU6TlEC-EquL-ZYziAy4DjshCIOnaDeAYI6jjSpDbr2VDtsKgyEsgbDcPdLRCPM4iYKvcjnV2x8aLowHGIW0zwYs9i-Ae+zHNB-RXPc-C1qiOSKJTWg0woDMoBzPMVEM8NuL0aLVli9p4qx8SUuOJ7GEQMIqH+ldAeMi7dyJvRjDMbLcveoGcfNFzjAJ1xxagSXrJym97KWcn00QTwaewunZclWAAqsYKztC2W4aZ-iWZeNmtu2znJJOXn+cF1ovaKgrbz3dAqA4FBLn94NlJ1UWTzRyHXs2sK701eArF0FHdyugBBRVhmWqBPwThmroAUTqP5U8gWQXp0fBZDAABqMBoi4K6C9-eBFioAAFZO5sYXl7su9v-xui4fsBtKPaoKhAczqghn1vRYBqsYMIa22oGog7F29-2ytardLhEW59LHI0ABIHM1YxPF+AFgSBRl4EhaFYU4SmgUv2hjAfyl4ESOe6AP3sHESU+tZQTxWjAWgdQAp4loOyD83JZDyXVtLawQh3CfC-iiaAyB-D7nCHQBI8wtIZwzvINYAB5BO5AR7AUyDKJ4FsAhLz+HrTwAAJdAYIwA4XknA9knIkHyRzMvRAQV5LziXgNfw8x3ADTAOURurB4BgAIREYhpDyFULAAAClvoCEEYJjGcHgPAMkkpOCYBMECAAlJwMAABNHECkc5hASCGdAYADzoEJGAVgvDoD-EMUCaAkYgn0DRE+IEbIljzHQNAfxZ1AnBPvlCGMr90SkgoH8P4xIYnwLiQkhxABJRJYJ3D+KnmAGM1gECckUYgBS6AbTBDAEIXsqiAm1IUi8M2ijUCpF0pwaUyggA)
+
+  - as a PNG:
+
+![PNG version of the lightcurve](https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/images/example.png "PNG version of the lightcurve")
+
 ## Documentation
 
 A tutorial is provided as part of the module: it is based, as is
@@ -53,21 +170,29 @@
 
 The
 [Vega-Lite Example Gallery](https://vega.github.io/vega-lite/examples/) has
-been converted to an
-[IHaskell notebook](https://github.com/DougBurke/hvega/blob/master/notebooks/VegaLiteGallery.ipynb)
+been converted to IHaskell notebooks in the
+[notebooks directory](https://github.com/DougBurke/hvega/tree/master/notebooks).
+Start with the
+[overview notebook](https://github.com/DougBurke/hvega/blob/master/notebooks/VegaLiteGallery.ipynb),
+which describes the set up, and then the individual
+sections have their own notebooks (with names of
+`VegaLiteGallery-<section>.ipynb`.
+
 Unfortunately the plots created by VegaEmbed **do not always appear**
 in the notebook when viewed with either GitHub's viewer or
 [ipynb viewer](http://nbviewer.jupyter.org/github/DougBurke/hvega/blob/master/notebooks/VegaLiteGallery.ipynb),
-but things seem much better when using Jupyter Lab (rather than
+but things seem better when using Jupyter Lab (rather than
 notebook) to create the notebooks (since Vega is natively
-supported in this environment). The notebooks have been re-created
+supported in this environment). However, the native support is
+for Vega-Lite version 1, and so many of the more-recent
+capabilities are either ignored or cause the visualization to
+fail.
+
+The notebooks have been re-created
 using Jupyter Lab (thanks to Tweag I/O's
 [JupyterWith environment](https://www.tweag.io/posts/2019-02-28-jupyter-with.html)), which should make the plots appear on GitHub (you may need
 to reload the notebooks as I find they don't display on the
 first try).
-
-The [notebooks directory](https://github.com/DougBurke/hvega/tree/master/notebooks)
-contains a poorly-curated set of examples and experiments with hvega.
 
 ## Differences to Elm Vega
 
diff --git a/default.nix b/default.nix
--- a/default.nix
+++ b/default.nix
@@ -1,2 +1,2 @@
-{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc882" }:
+{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc883" }:
 nixpkgs.pkgs.haskell.packages.${compiler}.callPackage ./hvega.nix { }
diff --git a/hvega.cabal b/hvega.cabal
--- a/hvega.cabal
+++ b/hvega.cabal
@@ -1,5 +1,5 @@
 name:                hvega
-version:             0.6.0.0
+version:             0.7.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>)
@@ -176,11 +176,13 @@
                        DataTests
                        EncodingTests
                        FillStrokeTests
+                       FilterTests
                        GeoTests
                        HyperlinkTests
                        ImageTests
                        InteractionTests
                        LegendTests
+                       MarkTests
                        NullTests
                        PositionTests
                        ProjectionTests
@@ -237,6 +239,24 @@
                      , directory
                      , filepath
                      , hvega
+                     , text
+  else
+    buildable:         False
+
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
+  
+executable    getbetelgeuse
+  hs-source-dirs:      tools/
+  main-is:             GetBetelgeuse.hs
+
+  if flag(tools)
+    build-depends:     aeson
+                     , base
+                     , bytestring
+                     , http-conduit >= 2.3 && < 2.4
+                     , tagsoup >= 0.14 && < 0.15
                      , text
   else
     buildable:         False
diff --git a/hvega.nix b/hvega.nix
--- a/hvega.nix
+++ b/hvega.nix
@@ -1,13 +1,15 @@
 { mkDerivation, aeson, aeson-pretty, base, bytestring, containers
 , filepath, stdenv, tasty, tasty-golden, text, unordered-containers
+, zlib
 }:
 mkDerivation {
   pname = "hvega";
-  version = "0.6.0.0";
+  version = "0.7.0.0";
   src = ./.;
   isLibrary = true;
   isExecutable = true;
   libraryHaskellDepends = [ aeson base text unordered-containers ];
+  executableHaskellDepends = [ zlib ];
   testHaskellDepends = [
     aeson aeson-pretty base bytestring containers filepath tasty
     tasty-golden text
diff --git a/images/example.png b/images/example.png
Binary files a/images/example.png and b/images/example.png differ
diff --git a/shell.nix b/shell.nix
--- a/shell.nix
+++ b/shell.nix
@@ -1,2 +1,2 @@
-{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc882" }:
+{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc883" }:
 (import ./default.nix { inherit nixpkgs compiler; }).env
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
@@ -2365,7 +2365,8 @@
 
 {-|
 
-In this example I display the same data as in 'starCount', but
+In this example (adapted from an example provided by Jo Wood)
+I display the same data as in 'starCount', but
 as two layers: the first is a histogram (using the 'Bar' mark),
 and the second displays the count value as a label with the
 'Text' mark.
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
@@ -13,10 +13,8 @@
 University of London. It was originally based on version @2.2.1@ but
 it has been updated to match later versions.  This module allows users
 to create a Vega-Lite specification, targeting __version 4__ of the
-<https://vega.github.io/schema/vega-lite/v4.json JSON schema>.  The
-ihaskell-hvega module provides an easy way to embed Vega-Lite
-visualizations in an IHaskell notebook (using
-<https://vega.github.io/vega-lite/usage/embed.html Vega-Embed>).
+<https://vega.github.io/schema/vega-lite/v4.json JSON schema>.
+Version 0.7 of @hvega@ supports version 4.7 of the Vega-Lite specification.
 
 Although this is based on the Elm module, there are differences, such
 as using type constructors rather than functions for many properties -
@@ -26,7 +24,11 @@
 requirement!
 
 Please see "Graphics.Vega.Tutorials.VegaLite" for an introduction
-to using @hvega@ to create visualizations.
+to using @hvega@ to create visualizations. The
+<http://hackage.haskell.org/package/ihaskell-hvega ihaskell-hvega>
+package provides an easy way to embed Vega-Lite
+visualizations in an IHaskell notebook (using
+<https://vega.github.io/vega-lite/usage/embed.html Vega-Embed>).
 
 == Example
 
@@ -46,44 +48,179 @@
 @
 
 In the following example, we'll assume the latter.
+The aim is to create the following visualization:
 
-Let's say we have the following plot declaration in a module:
+<<images/example.png>>
 
+However this is missing the interactive elements of the visualization, primarily
+selection and zooming in the top plot changes the axis ranges of the bottom two
+plots. This interactivity requires a Vega-Lite viewer such as
+<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxhJUBLAG2gFNY8oATeaAVywDpKb6A5eFloEADAF0wAXmlgA5ADVZkAL4AaYhDI86DfJBbsuWeAHNEFdk1pgAPGAAsK9SVKR4yRvvgBPD6qgAxvBUAWxUrLSeBhycAFZMYAC0YABM9gCsAByZ9gCcnCIqxGLOgeiIlCaMoC5uAB4UHvg1LlDQFlS0AGLl0ADqtBQmABbQnoiYxlSQpbXhAEa0VD2I0ADKFABekfgAjPazJDAd3b0b24y7AGwaYMrEasRe0PDVt5BssNN6o9AADshcAB6IEIADunBMFmGbHmbGQ9ACvVoq04SKwQIAIug2CYAEKfADWtCBwwAbrQTPAgcZkDpSRSqUCDNTFnQqCZaPDaIkUiI+YkRABmRK7fKxZDlSAPUqQMlIxBBMb4IguFq1YaDEbKsC7dIiQ4QSDGWCE6qQdB-eABCzeRgiTjpfwwbx-HZQP7oCirGZQHidJiMVDBBGPVpQMEUJjQYaMK4iA23I0IzoBdpS5pJo7zWDw2OZ8O1b0Wc11RgEXl8-y7BMlKB2lWCx3+FKOsRhwtGlFIpjekxNQiQMvOu0lLO1aCu92Qb06MnBaWd+7hju1bvoXuIKoFwuQJFUTBvTtGyhLQN6bT8QSRQ2tF1u8boLDehe3uaUlHn0jju8LJYrdYtndfY3zvdpoE6TwumoHQZh-CcTgA85gJuY87h-Vc72QYZ4AfZpyAoM9PEvWABCEX172nCZn0QBdMNqMsd07AiiL0FhfDgtDKM8ABHNgkHA1gKApTjj3qRpzXAyC9ExHxkDAZBvQCawACkkH42BvF1Ft+UKZdC3oo4G2-LjTyoL9jVMcxLBveCoGQIJpNcJgn3gb1y1FfwhXbUDk0wHV9FoBzPz7UTmMnPCoD4gSLCEkTfKgeAGgHMgpOnABZKyLDYKwiiXLN9IgTD1SOZA3QCI9d01IZRkufVQMs01zUta1bXtZs2inTxPVnCj-VoL9gyoUMGsjaN8zAeNE2Y9dN23EyxP3Q8mLEsyLJIsjbLQo0Iqop8X2mBKjU6TlEC-EquL-ZYziAy4DjshCIOnaDeAYI6jjSpDbr2VDtsKgyEsgbDcPdLRCPM4iYKvcjnV2x8aLowHGIW0zwYs9i-Ae+zHNB-RXPc-C1qiOSKJTWg0woDMoBzPMVEM8NuL0aLVli9p4qx8SUuOJ7GEQMIqH+ldAeMi7dyJvRjDMbLcveoGcfNFzjAJ1xxagSXrJym97KWcn00QTwaewunZclWAAqsYKztC2W4aZ-iWZeNmtu2znJJOXn+cF1ovaKgrbz3dAqA4FBLn94NlJ1UWTzRyHXs2sK701eArF0FHdyugBBRVhmWqBPwThmroAUTqP5U8gWQXp0fBZDAABqMBoi4K6C9-eBFioAAFZO5sYXl7su9v-xui4fsBtKPaoKhAczqghn1vRYBqsYMIa22oGog7F29-2ytardLhEW59LHI0ABIHM1YxPF+AFgSBRl4EhaFYU4SmgUv2hjAfyl4ESOe6AP3sHESU+tZQTxWjAWgdQAp4loOyD83JZDyXVtLawQh3CfC-iiaAyB-D7nCHQBI8wtIZwzvINYAB5BO5AR7AUyDKJ4FsAhLz+HrTwAAJdAYIwA4XknA9knIkHyRzMvRAQV5LziXgNfw8x3ADTAOURurB4BgAIREYhpDyFULAAAClvoCEEYJjGcHgPAMkkpOCYBMECAAlJwMAABNHECkc5hASCGdAYADzoEJGAVgvDoD-EMUCaAkYgn0DRE+IEbIljzHQNAfxZ1AnBPvlCGMr90SkgoH8P4xIYnwLiQkhxABJRJYJ3D+KnmAGM1gECckUYgBS6AbTBDAEIXsqiAm1IUi8M2ijUCpF0pwaUyggA the Vega Editor>.
+
+It is rather lengthy, as it includes
+data tranformation (sub-setting the data and creating a
+new column), automatic faceting (that is, creating separate plots
+for unique values of a data column), interactive elements
+(the ability to filter a plot by selecting a subset in
+another element), and some basic configuration and styling
+(primarily to change the text sizes). The
+"Graphics.Vega.Tutorials.VegaLite" tutorial should be
+reviewed to understand how the plot works!
+
+It's aim is to show the recent community measurements of the
+brightness of
+<https://en.wikipedia.org/wiki/Betelgeuse the star Betelgeuse>,
+which caused much interest in the Astronomical world at the
+start of 2020 as it became much fainter than normal
+(although it is massive enough to go supernova, it is not
+expected to happen for quite a while yet). The data shown
+is based on data collated by the
+<https://www.aavso.org/ AAVSO>, and converted to JSON format,
+with the primary columns of interest being \"@jd@\" (the
+date of the observation, in the
+<https://en.wikipedia.org/wiki/Julian_day Julian day> system),
+\"@magnitude@\" (the brightness of the star, reported
+as an
+<https://en.wikipedia.org/wiki/Apparent_magnitude apparent magnitude>),
+and \"@filterName\"@ (the filter through which the measurement was
+made). For display purposes we are only going to use the
+\"@Vis.@\" and \"@V@\" filters (the former is a by-eye estimate,
+which is less accurate but has the advantage of having been used
+for a long time, and the second is measured from a in image
+taken by a <https://en.wikipedia.org/wiki/Charge-coupled_device CCD detector>,
+which is more accurate and repeatable, but more costly to obtain),
+and the date field is going to be converted into the number of
+days since the start of 2020 (via a little bit of subtraction).
+For \"historical reasons\", the magnitude system used by Astronomers
+to measure how bright a system is reversed, so that larger magnitudes
+mean fainter systems. For this reason, the magnitude axis is reversed
+in this visualization, so that as Betelgeuse dims the values drop.
+
 @
-\{\-\# language OverloadedStrings \#\-\}
+\{\-\# LANGUAGE OverloadedStrings \#\-\}
 
-vl1 =
-  let desc = "A very exciting bar chart"
+betelgeuse =
+  let desc = \"How has Betelgeuse's brightness varied, based on data collated by AAVSO (https:\/\/www.aavso.org\/). \" ++
+             \"You should also look at https:\/\/twitter.com\/betelbot and https:\/\/github.com\/hippke\/betelbot. \" ++
+             \"It was all the rage on social media at the start of 2020.\"
 
-      dat = 'VL.dataFromRows' ['VL.Parse' [("start", 'VL.FoDate' "%Y-%m-%d")]]
-            . 'VL.dataRow' [("start", 'VL.Str' "2011-03-25"), ("count", 'VL.Number' 23)]
-            . 'VL.dataRow' [("start", 'VL.Dtr' "2011-04-02"), ("count", 'VL.Number' 45)]
-            . 'VL.dataRow' [("start", 'VL.Str' "2011-04-12"), ("count", 'VL.Number' 3)]
+      titleStr = \"Betelegeuse's magnitude measurements, collated by AAVSO\"
 
-      barOpts = ['VL.MOpacity' 0.4, 'VL.MColor' "teal"]
+      -- height and width of individual plots (in pixels)
+      w = 'VL.width' 600
+      h = 'VL.height' 150
 
-      enc = 'VL.encoding'
-            . 'VL.position' 'VL.X' ['VL.PName' "start", 'VL.PmType' 'VL.Temporal', 'VL.PAxis' ['VL.AxTitle' "Inception date"]]
-            . 'VL.position' 'VL.Y' ['VL.PName' "count", 'VL.PmType' 'VL.Quantitative']
+      -- Define the properties used for the "position" channels. For this example
+      -- it makes sense to define as functions since they are used several times.
+      --
+      pos1Opts fld ttl = ['VL.PName' fld, 'VL.PmType' 'VL.Quantitative', 'VL.PAxis' ['VL.AxTitle' ttl]]
+      x1Opts = pos1Opts \"days\" \"Days since January 1, 2020\"
+      y1Opts = pos1Opts \"magnitude\" \"Magnitude\" ++ ['VL.PSort' ['VL.Descending'], y1Range]
+      y1Range = 'VL.PScale' ['VL.SDomain' ('VL.DNumbers' [-1, 3])]
 
-  in 'VL.toVegaLite' ['VL.description' desc, 'VL.background' "white"
-                , dat [], 'VL.mark' 'VL.Bar' barOpts, enc []]
-@
+      -- The filter name is used as a facet, but also to define the
+      -- color and shape of the points.
+      --
+      filtOpts = ['VL.MName' \"filterName\", 'VL.MmType' 'VL.Nominal']
+      filtEnc = 'VL.color' ('VL.MLegend' ['VL.LTitle' \"Filter\", 'VL.LTitleFontSize' 16, 'VL.LLabelFontSize' 14] : filtOpts)
+                . 'VL.shape' filtOpts
 
-We can inspect how the encoded JSON looks like in an GHCi session:
+      -- In an attempt to make the V filter results visible, I have chosen
+      -- to use open symbols. It doesn't really work out well.
+      --
+      circle = 'VL.mark' 'VL.Point' ['VL.MOpacity' 0.5, 'VL.MFilled' False]
 
-@
-> 'A.encode' $ 'VL.fromVL' vl1
-> "{\"mark\":{\"color\":\"teal\",\"opacity\":0.4,\"type\":\"bar\"},\"data\":{\"values\":[{\"start\":\"2011-03-25\",\"count\":23},{\"start\":\"2011-04-02\",\"count\":45},{\"start\":\"2011-04-12\",\"count\":3}],\"format\":{\"parse\":{\"start\":\"date:'%Y-%m-%d'\"}}},\"$schema\":\"https:\/\/vega.github.io\/schema\/vega-lite\/v4.json\",\"encoding\":{\"x\":{\"field\":\"start\",\"type\":\"temporal\",\"axis\":{\"title\":\"Inception date\"}},\"y\":{\"field\":\"count\",\"type\":\"quantitative\"}},\"background\":\"white\",\"description\":\"A very exciting bar chart\"}"
-@
+      -- What is plotted in the "overview" plot?
+      --
+      encOverview = 'VL.encoding'
+                    . 'VL.position' 'VL.X' x1Opts
+                    . 'VL.position' 'VL.Y' y1Opts
+                    . filtEnc
 
-The produced JSON can then be processed with vega-lite, which renders the following image:
+      -- Select roughly the last year's observations (roughly the length of
+      -- time that Betelgeuse is visible)
+      --
+      xlim = ('VL.Number' (-220), 'VL.Number' 100)
+      ylim = ('VL.Number' (-0.5), 'VL.Number' 2.5)
+      overview = 'VL.asSpec' [ w
+                        , h
+                        , encOverview []
+                        , 'VL.selection'
+                          . 'VL.select' selName 'VL.Interval' ['VL.Encodings' ['VL.ChX', 'VL.ChY']
+                                                    , 'VL.SInitInterval' (Just xlim) (Just ylim)
+                                                    ]
+                          $ []
+                        , circle
+                        ]
 
-<<images/example.png>>
+      -- What is plotted in the "detail" plot?
+      --
+      selName = \"brush\"
+      pos2Opts fld = [ 'VL.PName' fld, 'VL.PmType' 'VL.Quantitative', 'VL.PAxis' ['VL.AxNoTitle']
+                     , 'VL.PScale' ['VL.SDomain' ('VL.DSelectionField' selName fld)] ]
+      x2Opts = pos2Opts \"days\"
+      y2Opts = pos2Opts \"magnitude\" ++ ['VL.PSort' ['VL.Descending']]
 
-which can also be
-<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuMxIGMD2Abb8qUALgKay6QA0U2ADrJgJbECeRADAHQAsNkbOqSKQARgkgBfKuCgATWMVhFQECJABuFAK6kAzkQDastekh6l8YiIBMHAIz2AtBwDMTmwFZqUHNoB21mg2rtImahgWCEFQdo4uPC42PljYATE8nmGmEJGWMZBxzhyJ9sn8foFEoeEAujKmkABmBHAxGAzwesJoedEiCmQoAOQApACaTqPQU3LDUpKy2VAAJHqYABakcCIbxMR0eigA9McapADmsFwXLBvaolxM2MfrW3Bnl7BOuCykZ64uAArPTYfzUWSQUj+HByJj+C4qcKQAAeSJyUCaTFIuDkIiiVghGIErCEIjI0DoBAoRJykFgKKYBl6AhYuB6UAAkjDSHRiM9-GBBsJFqZlup2CysTi8WhUukUoIOZAAI7aWCBFiKJjnKRLBpQcSYRAXeBpfyyqAAdw2f1pkDk+kw8CYfIFIgAgmBzvBWGBSCjmPyEWBxPAwJt+gbUv4sYjeotJEA displayed in the Vega Editor>.
+      encDetail = 'VL.encoding'
+                  . 'VL.position' 'VL.X' x2Opts
+                  . 'VL.position' 'VL.Y' y2Opts
+                  . filtEnc
 
+      detail = 'VL.asSpec' [ w
+                      , h
+                      , encDetail []
+                      , circle
+                      ]
+
+      -- Control the labelling of the faceted plots. Here we move the
+      -- label so that it appears at the top-right corner of each plot
+      -- and remove the title.
+      --
+      headerOpts = [ 'VL.HLabelFontSize' 16
+                   , 'VL.HLabelAlign' 'VL.AlignRight'
+                   , 'VL.HLabelAnchor' 'VL.AEnd'
+                   , 'VL.HLabelPadding' (-24)
+                   , 'VL.HNoTitle'
+                   , 'VL.HLabelExpr' \"'Filter: ' + datum.label\"
+                   ]
+
+      -- The "detail" plot has multiple rows, one for each filter.
+      --
+      details = 'VL.asSpec' [ 'VL.columns' 1
+                       , 'VL.facetFlow' [ 'VL.FName' \"filterName\"
+                                   , 'VL.FmType' 'VL.Nominal'
+                                   , 'VL.FHeader' headerOpts
+                                   ]
+                       , 'VL.spacing' 10
+                       , 'VL.specification' detail
+                       ]
+
+  in 'VL.toVegaLite' [ 'VL.description' desc
+                , 'VL.title' titleStr ['VL.TFontSize' 18]
+                , 'VL.dataFromUrl' \"https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/betelgeuse-2020-03-19.json\" []
+                , 'VL.transform'
+                  -- concentrate on the two filters with a reasonable number of points
+                  . 'VL.filter' ('VL.FExpr' \"datum.filterName[0] === \'V\'\")
+                  -- remove some \"outliers\"
+                  . 'VL.filter' ('VL.FExpr' \"datum.magnitude < 4\")
+                  -- subtract Jan 1 2020 (start of day, hence the .0 rather than .5)
+                  . 'VL.calculateAs' \"datum.jd - 2458849.0\" \"days\"
+                  $ []
+                , 'VL.vConcat' [overview, details]
+                , 'VL.configure'
+                  -- Change axis titles from bold- to normal-weight,
+                  -- and increase the size of the labels
+                  . 'VL.configuration' ('VL.Axis' ['VL.TitleFontWeight' 'VL.Normal', 'VL.TitleFontSize' 16, 'VL.LabelFontSize' 14])
+                  $ []
+                ]
+
+@
+
+The 'VL.fromVL' function will create the JSON representation of the visualization,
+which can then be passed to a Vega-Lite viewer (or a routine like 'VL.toHtmlFile'
+can be used to create a HTML file that will display the visualization using the
+<https://github.com/vega/vega-embed Vega-Embed> Javascript library).
+
 Output can be achieved in a Jupyter Lab session with the @vlShow@ function,
 provided by @ihaskell-vega@, or 'VL.toHtmlFile' can be used to write out a page of
 HTML that includes pointer to JavaScript files which will display a Vega-Lite
@@ -342,6 +479,7 @@
        , VL.ColorGradient(..)
        , VL.GradientProperty(..)
        , VL.TextDirection(..)
+       , VL.BlendMode(..)
 
          -- ** Cursors
          --
@@ -607,6 +745,7 @@
          -- $axisconfig
 
        , VL.AxisConfig(..)
+       , VL.AxisChoice(..)
 
          -- ** Legend Configuration Options
          --
@@ -668,6 +807,10 @@
          --
          -- $update
 
+         -- ** Version 0.7
+         --
+         -- $update0700
+
          -- ** Version 0.6
          --
          -- $update0600
@@ -1055,6 +1198,54 @@
 -- $update
 -- The following section describes how to update code that used
 -- an older version of @hvega@.
+
+-- $update0700
+-- The @0.7.0.0@ release updates @hvega@ to support version 4.7 of
+-- the Vega-Lite schema.
+--
+-- __New functionality__
+--
+-- The 'VL.BlendMode' type has been added for controlling how marks blend
+-- with their background. This is used with the new 'VL.MBlend' constructor
+-- for marks.
+--
+-- __Breaking Change__
+--
+-- The axis style options for specific data- or mark- types
+-- ('VL.AxisBand', 'VL.AxisDiscrete', 'VL.AxisPoint',
+-- 'VL.AxisQuantitative', and 'VL.AxisTemporal') have been changed to
+-- accept an additional argument (the new 'VL.AxisChoice' type)
+-- which defines which axis (X, Y, or both) the configuration should be
+-- applied to. This is to support new axis configuration options added
+-- in Vega-Lite 4.7.0.
+--
+-- The @ChTooltip@ 'VL.Channel' constructor has been removed as support
+-- for this channel type was dropped in Vega-Lite 4.
+--
+-- __New constructors__
+--
+-- The 'VL.ScaleDomain' type has gained 'VL.DSelectionField' and 'VL.DSelectionChannel'
+-- constructors, which allow you to link a scale (e.g. an axis) to a selection that
+-- is projected over multiple fields or encodings.
+--
+-- The 'VL.Operation' type has gained the 'VL.Product' specifier from Vega-Lite
+-- 4.6.0.
+--
+-- The 'VL.TextChannel' has gained 'VL.TStrings' to support multi-line labels.
+--
+-- The 'VL.VAlign' type has gained 'VL.AlignLineTop' and 'VL.AlignLineBottom'
+-- (Vega-Lite 4.6.0).
+--
+-- 'VL.LineBreakStyle' has been added to 'VL.ConfigurationProperty'.
+--
+-- The height of multi-line axis labels can now be set with the
+-- 'VL.LabelLineHeight' and 'VL.AxLabelLineHeight' properties of the
+-- 'VL.AxisConfig' and 'VL.AxisProperty' types (Vega-Lite 4.6.0).
+--
+-- Numeric filter ranges, specified with 'VL.FRange',
+-- can now be lower- or upper-limits -
+-- 'VL.NumberRangeLL' and 'VL.NumberRangeUL' respectively -
+-- added to the 'VL.FilterRange' type.
 
 -- $update0600
 -- The @0.6.0.0@ release updates @hvega@ to support version 4.5 of
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
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings #-}
 
 {-|
@@ -24,6 +25,7 @@
        , ScaleConfig(..)
        , RangeConfig(..)
        , AxisConfig(..)
+       , AxisChoice(..)
        , LegendConfig(..)
        , TitleConfig(..)
 
@@ -40,6 +42,10 @@
 
 import Data.Aeson ((.=), object)
 
+#if !(MIN_VERSION_base(4, 12, 0))
+import Data.Monoid ((<>))
+#endif
+
 import Graphics.Vega.VegaLite.Core
   ( AxisProperty
   , axisProperty
@@ -120,16 +126,24 @@
   , LabelledSpec
   , PropertySpec
   )
-  
 
+
 {-|
 
 Type of configuration property to customise. See the
 <https://vega.github.io/vega-lite/docs/config.html Vega-Lite documentation>
-for details.
+for details. There are multiple ways to configure the properties
+of an axis, as discussed in the Vega-Lite
+<https://vega.github.io/vega-lite/docs/axis.html#config axis configuration>
+documentation.
 
 Used by 'configuration'.
 
+In @version 0.7.0.0@, the 'AxisBand' , 'AxisDiscrete', 'AxisPoint',
+'AxisQuantitative', and 'AxisTemporal' were changed to accept an
+additional argument ('AxisChoice'), to define which axis the configuration
+should be applied to.
+
 In @version 0.6.0.0@:
 
 - the @Autosize@, @Background@, @CountTitle@, @FieldTitle@, @Legend@,
@@ -190,13 +204,13 @@
       --   @since 0.6.0.0
     | Axis [AxisConfig]
       -- ^ The default appearance of axes.
-    | AxisBand [AxisConfig]
+    | AxisBand AxisChoice [AxisConfig]
       -- ^ The default appearance of axes with band scaling.
       --
       --   See also 'AxisDiscrete'.
     | AxisBottom [AxisConfig]
       -- ^ The default appearance of the bottom-side axes.
-    | AxisDiscrete [AxisConfig]
+    | AxisDiscrete AxisChoice [AxisConfig]
       -- ^ The default appearance of axes with point or band scales.
       --
       --   See also 'AxisBand' and 'AxisPoint'.
@@ -204,19 +218,19 @@
       --   @since 0.6.0.0
     | AxisLeft [AxisConfig]
       -- ^ The default appearance of the left-side axes.
-    | AxisPoint [AxisConfig]
+    | AxisPoint AxisChoice [AxisConfig]
       -- ^ The default appearance of axes with point scales.
       --
       --   See also 'AxisDiscrete'.
       --
       --   @since 0.6.0.0
-    | AxisQuantitative [AxisConfig]
+    | AxisQuantitative AxisChoice [AxisConfig]
       -- ^ The default appearance of quantitative axes.
       --
       --   @since 0.6.0.0
     | AxisRight [AxisConfig]
       -- ^ The default appearance of the right-side axes.
-    | AxisTemporal [AxisConfig]
+    | AxisTemporal AxisChoice [AxisConfig]
       -- ^ The default appearance of temporal axes.
       --
       --   @since 0.6.0.0
@@ -323,6 +337,14 @@
       --   @since 0.6.0.0
     | LineStyle [MarkProperty]
       -- ^ The default appearance of line marks.
+    | LineBreakStyle T.Text
+      -- ^ The delimiter, such as a newline character, upon which to break text
+      --   strings into multiple lines. This can be over-ridden by mark or style configuration
+      --   settings.
+      --
+      --   Added in Vega-Lite 4.6.0.
+      --
+      --   @since 0.7.0.0
     | MarkStyle [MarkProperty]
       -- ^ The default mark appearance.
     | MarkNamedStyles [(StyleLabel, [MarkProperty])]
@@ -449,9 +471,30 @@
       --   used instead.
 
 
+-- | Which axis should the configuration be applied to?
+--
+--   Added in Vega-Lite 4.7.0.
+--
+--   @since 0.7.0.0
+data AxisChoice
+  = AxXY
+    -- ^ Apply the configuration to both axes.
+    --
+    --   This was the default behavior prior to @0.7.0.0@.
+  | AxX
+    -- ^ Select the X axis.
+  | AxY
+    -- ^ Select the Y axis.
+
+
 toAxis :: T.Text -> [AxisConfig] -> LabelledSpec
-toAxis lbl acs = lbl .= object (map axisConfigProperty acs)
+toAxis lbl acs = ("axis" <> lbl) .= object (map axisConfigProperty acs)
 
+toAxisChoice :: AxisChoice -> T.Text -> [AxisConfig] -> LabelledSpec
+toAxisChoice AxXY lbl = toAxis lbl
+toAxisChoice AxX lbl = toAxis ("X" <> lbl)
+toAxisChoice AxY lbl = toAxis ("Y" <> lbl)
+
 aprops_ :: T.Text -> [AxisProperty] -> LabelledSpec
 aprops_ f mps = f .= object (map axisProperty mps)
 
@@ -459,18 +502,18 @@
 configProperty :: ConfigurationProperty -> LabelledSpec
 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 (Axis acs) = toAxis "" acs
+configProperty (AxisBand c acs) = toAxisChoice c "Band" acs
+configProperty (AxisBottom acs) = toAxis "Bottom" acs
+configProperty (AxisDiscrete c acs) = toAxisChoice c "Discrete" acs
+configProperty (AxisLeft acs) = toAxis "Left" acs
+configProperty (AxisPoint c acs) = toAxisChoice c "Point" acs
+configProperty (AxisQuantitative c acs) = toAxisChoice c "Quantitative" acs
+configProperty (AxisRight acs) = toAxis "Right" acs
+configProperty (AxisTemporal c acs) = toAxisChoice c "Temporal" acs
+configProperty (AxisTop acs) = toAxis "Top" acs
+configProperty (AxisX acs) = toAxis "X" acs
+configProperty (AxisY acs) = toAxis "Y" acs
 
 -- configProperty (AxisNamedStyles [(nme, mps)]) = "style" .= object [aprops_ nme mps]
 configProperty (AxisNamedStyles styles) =
@@ -497,6 +540,8 @@
 configProperty (LegendStyle lcs) = "legend" .= object (map legendConfigProperty lcs)
 configProperty (LineStyle mps) = mprops_ "line" mps
 
+configProperty (LineBreakStyle s) = "lineBreak" .= s
+
 configProperty (MarkStyle mps) = mprops_ "mark" mps
 -- configProperty (MarkNamedStyles [(nme, mps)]) = "style" .= object [mprops_ nme mps]
 configProperty (MarkNamedStyles styles) =
@@ -1200,6 +1245,9 @@
       -- ^ The named styles - generated with 'AxisNamedStyles' - to apply to the
       --   axis or axes.
       --
+      --   Added in Vega-Lite 4.7.0 (although accidentally supported in @hvega@
+      --   before this release).
+      --
       --   @since 0.6.0.0
     | BandPosition Double
       -- ^ The default axis band position.
@@ -1311,6 +1359,12 @@
       --   @since 0.4.0.0
     | LabelLimit Double
       -- ^ The maximum width of a label, in pixels.
+    | LabelLineHeight Double
+      -- ^ The line height, in pixels, for multi-line label text.
+      --
+      --   Added in Vega-Lite 4.6.0.
+      --
+      --   @since 0.7.0.0
     | LabelOffset Double
       -- ^ The pixel offset for labels, in addition to 'TickOffset'.
       --
@@ -1459,6 +1513,7 @@
 axisConfigProperty (LabelFontStyle s) = "labelFontStyle" .= s
 axisConfigProperty (LabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw
 axisConfigProperty (LabelLimit x) = "labelLimit" .= x
+axisConfigProperty (LabelLineHeight x) = "labelLineHeight" .= x
 axisConfigProperty (LabelOffset x) = "labelOffset" .= x
 axisConfigProperty (LabelOpacity x) = "labelOpacity" .= x
 axisConfigProperty (LabelOverlap strat) = "labelOverlap" .= overlapStrategyLabel strat
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
@@ -1313,6 +1313,12 @@
       -- ^ The maximum width of a label, in pixels.
       --
       --   @since 0.4.0.0
+    | AxLabelLineHeight Double
+      -- ^ The line height, in pixels, for multi-line label text.
+      --
+      --   Added in Vega-Lite 4.6.0.
+      --
+      --   @since 0.7.0.0
     | AxLabelOffset Double
       -- ^ The pixel offset for labels, in addition to 'AxTickOffset'.
       --
@@ -1541,6 +1547,7 @@
 axisProperty (AxLabelFontStyle s) = "labelFontStyle" .= s
 axisProperty (AxLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw
 axisProperty (AxLabelLimit x) = "labelLimit" .= x
+axisProperty (AxLabelLineHeight x) = "labelLineHeight" .= x
 axisProperty (AxLabelOffset x) = "labelOffset" .= x
 axisProperty (AxLabelOpacity x) = "labelOpacity" .= x
 axisProperty (AxLabelOverlap s) = "labelOverlap" .= overlapStrategyLabel s
@@ -1751,7 +1758,7 @@
       --   'Data.Function.&').
       --
       --   @
-      --   'filter' ('FRange' "date" ('DateRange' ['Graphics.Vega.VegaLite.DTYear' 2010] ['Graphics.Vega.VegaLite.DTYear' 2017])
+      --   'filter' ('FRange' "date" ('NumberRange' 2010 2017)
       --           & 'FilterOpTrans' ('MTimeUnit' 'Graphics.Vega.VegaLite.Year')
       --           & 'FCompose'
       --           )
@@ -1902,6 +1909,8 @@
 filterProperty (FRange field vals) =
   let ans = case vals of
               NumberRange mn mx -> map toJSON [mn, mx]
+              NumberRangeLL mn -> [toJSON mn, A.Null]
+              NumberRangeUL mx -> [A.Null, toJSON mx]
               DateRange dMin dMax -> [process dMin, process dMax]
 
       process [] = A.Null
@@ -1933,14 +1942,28 @@
 trFilterSpec mchan fi = object (markChannelProperty mchan <> filterProperty fi)
 
 
-{-|
+-- | A pair of filter range data values, used with 'FRange'.
 
-A pair of filter range data values. The first argument is the inclusive minimum
-vale to accept and the second the inclusive maximum.
--}
 data FilterRange
     = NumberRange Double Double
+      -- ^ Select between these two values (both limits are inclusive).
+    | NumberRangeLL Double
+      -- ^ A lower limit (inclusive).
+      --
+      --   @since 0.7.0.0
+    | NumberRangeUL Double
+      -- ^ An upper limit (inclusive).
+      --
+      --   @since 0.7.0.0
     | DateRange [DateTime] [DateTime]
+      -- ^ Select between these two dates (both limits are inclusive).
+      --
+      --   If a limit is the empty list then the filter is treated as
+      --   a limit only on the other value, so
+      --   @DateRange [] ['Graphics.Vega.VegaLite.DTYear' 2019]@
+      --   acts as an upper-limit on the date range. One of the two
+      --   limits __should__ be defined, but there is no enforcement
+      --   of this.
 
 
 -- | Types of hyperlink channel property used for linking marks or text to URLs.
@@ -2184,7 +2207,7 @@
     | TTimeUnit TimeUnit
       -- ^ Time unit aggregation of field values when encoding with a text channel.
     | TString T.Text
-      -- ^ A literal value for encoding a text property channel
+      -- ^ A literal value for encoding a text property channel. See also 'TStrings'.
       --
       --   This can be useful for a text annotation, such as:
       --
@@ -2196,6 +2219,10 @@
       --   @
       --
       --   @since 0.5.0.0
+    | TStrings [T.Text]
+      -- ^ A multi-line value. See also 'TString'.
+      --
+      --   @since 0.7.0.0
 
 textChannelProperty :: TextChannel -> [LabelledSpec]
 textChannelProperty (TName s) = [field_  s]
@@ -2215,6 +2242,7 @@
 textChannelProperty (TSelectionCondition selName ifClause elseClause) =
   selCond_ textChannelProperty selName ifClause elseClause
 textChannelProperty (TString s) = ["value" .= s]
+textChannelProperty (TStrings xs) = ["value" .= xs]
 
 
 -- | Properties of an ordering channel used for sorting data fields.
@@ -3416,7 +3444,7 @@
 
 @
 transLS = 'transform'
-          . 'regression' \"yraw\" \"xraw\" [ 'LsAs' \"xrg\" \"yrg\" ]
+          . 'regression' \"yraw\" \"xraw\" [ 'RgAs' \"xrg\" \"yrg\" ]
 
 encRaw = 'encoding'
          . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"xraw\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]
@@ -4130,7 +4158,7 @@
       jj :: A.ToJSON a => a -> Maybe A.Value
       jj = Just . toJSON
 
-      res = case lfields of               
+      res = case lfields of
              LuFields fs -> ( jj fs, Nothing, Nothing )
              LuFieldAs fas -> ( get1 fas, get2 fas, Nothing )
              LuAs s -> ( Nothing, jj s, Nothing )
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
@@ -580,18 +580,32 @@
 
 data VAlign
     = AlignTop
-      -- ^ The position refers to the top of the text.
+      -- ^ The position refers to the top of the text, calculated relative to
+      --   the font size. Also see 'AlignLineTop'.
     | AlignMiddle
       -- ^ The middle of the text.
     | AlignBottom
       -- ^ The position refers to the bottom of the text, including
-      --   descenders, like g.
+      --   descenders, like g. This is calculated relative to the
+      --   font size. Also see 'AlignLineBottom'.
     | 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
+    | AlignLineTop
+      -- ^ Similar to 'AlignTop', but relative to the line height, not font size.
+      --
+      --   This was added in Vega-Lite 4.6.0.
+      --
+      --   @since 0.7.0.0
+    | AlignLineBottom
+      -- ^ Similar to 'AlignBottom', but relative to the line height, not font size.
+      --
+      --   This was added in Vega-Lite 4.6.0.
+      --
+      --   @since 0.7.0.0
 
 hAlignLabel :: HAlign -> T.Text
 hAlignLabel AlignLeft = "left"
@@ -603,6 +617,8 @@
 vAlignLabel AlignMiddle = "middle"
 vAlignLabel AlignBottom = "bottom"
 vAlignLabel AlignBaseline = "alphabetic"
+vAlignLabel AlignLineTop = "line-top"
+vAlignLabel AlignLineBottom = "line-bottom"
 
 {-|
 
@@ -1056,6 +1072,9 @@
 --   'Graphics.Vega.VegaLite.BLChannel', 'Graphics.Vega.VegaLite.BLChannelEvent',
 --   'Graphics.Vega.VegaLite.ByChannel', and 'Graphics.Vega.VegaLite.Encodings'
 --   constructors.
+--
+--   Changed in @0.7.0.0@: the @ChTooltip@ channel was removed as it was
+--   dropped in Vega-Lite 4.0.
 
 -- assuming this is based on schema 3.3.0 #/definitions/SingleDefUnitChannel
 
@@ -1094,8 +1113,6 @@
       -- ^ @since 0.4.0.0
     | ChText
       -- ^ @since 0.4.0.0
-    | ChTooltip
-      -- ^ @since 0.4.0.0
 
 
 channelLabel :: Channel -> T.Text
@@ -1120,7 +1137,6 @@
 channelLabel ChStrokeWidth = "strokeWidth"
 channelLabel ChStrokeOpacity = "strokeOpacity"
 channelLabel ChText = "text"
-channelLabel ChTooltip = "tooltip"
 
 
 {-|
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
@@ -26,6 +26,7 @@
        , ColorGradient(..)
        , GradientProperty(..)
        , TextDirection(..)
+       , BlendMode(..)
 
          -- not for external export
        , mprops_
@@ -60,6 +61,7 @@
   , VAlign
   , fromColor
   , fromDS
+  , fromT
   , cursorLabel
   , fontWeightSpec
   , orientationSpec
@@ -243,6 +245,12 @@
       --
       --   The ideal value for this is either @0@ (preferred by statisticians)
       --   or @1@ (the Vega-Lite default value, D3 example style).
+    | MBlend BlendMode
+      -- ^ How should the item be blended with its background?
+      --
+      --   Added in Vega-Lite 4.6.0.
+      --
+      --   @since 0.7.0.0
     | MBorders [MarkProperty]
       -- ^ Border properties for an 'ErrorBand' mark. See also 'MNoBorders'.
       --
@@ -627,6 +635,10 @@
 
 markProperty (MBinSpacing x) = "binSpacing" .= x
 
+-- only available in AreaConfig, BarConfig, LineConfig, MarkConfig,
+--                   MarkDef, OverlayMarkDef, RectConfig, TickConfig
+markProperty (MBlend bl) = "blend" .= blendModeSpec bl
+
 -- only available in ErrorBand[Config|Def], PartsMixins<ErrorBandPart>
 markProperty MNoBorders = "borders" .= False
 markProperty (MBorders mps) = mprops_ "borders" mps
@@ -1018,3 +1030,71 @@
 textdirLabel :: TextDirection -> T.Text
 textdirLabel LTR = "ltr"
 textdirLabel RTL = "rtl"
+
+
+-- | The blend mode for drawing an item on its background.
+--
+--   This is based on CSS <https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode mix-blend-mode>
+--   and the default is 'BMNormal' (at least for SVG output).
+--
+--   Added in Vega-Lite 4.6.0.
+--
+--   It is currently unclear how this works with canvas outputs
+--   (see Vega-Lite <https://github.com/vega/vega-lite/pull/6033 #6033>
+--   and <https://github.com/vega/vega-lite/issues/6100 #6100>
+--   for more information).
+--
+--   @since 0.7.0.0
+
+data BlendMode
+  = BMNormal
+    -- ^ @normal@ mode (this maps to @null@ in Vega-Lite).
+  | BMMultiply
+    -- ^ @multiply@ mode.
+  | BMScreen
+    -- ^ @screen@ mode.
+  | BMOverlay
+    -- ^ @overlay@ mode.
+  | BMDarken
+    -- ^ @daren@ mode.
+  | BMLighten
+    -- ^ @lighten@ mode.
+  | BMColorDodge
+    -- ^ @color-dodge@ mode.
+  | BMColorBurn
+    -- ^ @color-burn@ mode.
+  | BMHardLight
+    -- ^ @hard-light@ mode.
+  | BMSoftLight
+    -- ^ @soft-light@ mode.
+  | BMDifference
+    -- ^ @difference@ mode.
+  | BMExclusion
+    -- ^ @exclusion@ mode.
+  | BMHue
+    -- ^ @hue@ mode.
+  | BMSaturation
+    -- ^ @saturation@ mode.
+  | BMColor
+    -- ^ @color@ mode.
+  | BMLuminosity
+    -- ^ @luminosity@ mode.
+
+
+blendModeSpec :: BlendMode -> VLSpec
+blendModeSpec BMNormal = A.Null
+blendModeSpec BMMultiply = fromT "multiply"
+blendModeSpec BMScreen = fromT "screen"
+blendModeSpec BMOverlay = fromT "overlay"
+blendModeSpec BMDarken = fromT "darken"
+blendModeSpec BMLighten = fromT "lighten"
+blendModeSpec BMColorDodge = fromT "color-dodge"
+blendModeSpec BMColorBurn = fromT "color-burn"
+blendModeSpec BMHardLight = fromT "hard-light"
+blendModeSpec BMSoftLight = fromT "soft-light"
+blendModeSpec BMDifference = fromT "difference"
+blendModeSpec BMExclusion = fromT "exclusion"
+blendModeSpec BMHue = fromT "hue"
+blendModeSpec BMSaturation = fromT "saturation"
+blendModeSpec BMColor = fromT "color"
+blendModeSpec BMLuminosity = fromT "luminosity"
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
@@ -29,10 +29,14 @@
 
 
 import Graphics.Vega.VegaLite.Foundation
-  ( fromT
+  ( Channel
+  , FieldName
+  , fromT
+  , channelLabel
   )
 import Graphics.Vega.VegaLite.Specification
   ( VLSpec
+  , SelectionLabel
   )
 import Graphics.Vega.VegaLite.Time
   ( DateTime
@@ -55,8 +59,25 @@
       -- ^ String values that define a scale domain.
     | DDateTimes [[DateTime]]
       -- ^ Date-time values that define a scale domain.
-    | DSelection T.Text
+    | DSelection SelectionLabel
       -- ^ Scale domain based on a named interactive selection.
+      --   See also 'DSelectionField' and 'DSelectionChannel', which should
+      --   be used when a selection is
+      --   [projected](https://vega.github.io/vega-lite/docs/project.html)
+      --   over multiple fields or encodings.
+      --
+      --   In @0.7.0.0@ the argument type was changed to @SelectionLabel@
+      --   (which is a type synonym for @Text@).
+    | DSelectionField SelectionLabel FieldName
+      -- ^ Use the given selection /and/ associated field, when the selection
+      --   is projected over multiple fields or encodings.
+      --
+      --   @since 0.7.0.0
+    | DSelectionChannel SelectionLabel Channel
+      -- ^ Use the given selection /and/ associated encoding, when the selection
+      --   is projected over multiple fields or encodings.
+      --
+      --   @since 0.7.0.0
     | DUnionWith ScaleDomain
       -- ^ Combine the domain of the data with the provided domain.
       --
@@ -79,6 +100,10 @@
 scaleDomainSpec (DDateTimes dts) = toJSON (map (object . map dateTimeProperty) dts)
 scaleDomainSpec (DStrings cats) = toJSON (map toJSON cats)
 scaleDomainSpec (DSelection selName) = object ["selection" .= selName]
+scaleDomainSpec (DSelectionField selName field) = object [ "selection" .= selName
+                                                         , "field" .= field ]
+scaleDomainSpec (DSelectionChannel selName ch) = object [ "selection" .= selName
+                                                        , "encoding" .= channelLabel ch ]
 scaleDomainSpec (DUnionWith sd) = object ["unionWith" .= scaleDomainSpec sd]
 scaleDomainSpec Unaggregated = "unaggregated"
 
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
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE OverloadedStrings #-}
 
 {-|
@@ -8,7 +7,7 @@
 
 Maintainer  : dburke.gw@gmail.com
 Stability   : unstable
-Portability : CPP, OverloadedStrings
+Portability : OverloadedStrings
 
 Time-related types.
 
@@ -29,10 +28,6 @@
 import qualified Data.Text as T
 
 import Data.Aeson ((.=), object)
-
-#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)
diff --git a/src/Graphics/Vega/VegaLite/Transform.hs b/src/Graphics/Vega/VegaLite/Transform.hs
--- a/src/Graphics/Vega/VegaLite/Transform.hs
+++ b/src/Graphics/Vega/VegaLite/Transform.hs
@@ -140,6 +140,12 @@
       -- ^ Minimum field value to be used in an aggregation operation.
     | Missing
       -- ^ Count of @null@ or @undefined@ field value to be used in an aggregation operation.
+    | Product
+      -- ^ Product of field values to be used in an aggregate operation.
+      --
+      --   This was added in Vega-Lite 4.6.0.
+      --
+      --   @since 0.7.0.0
     | Q1
       -- ^ Lower quartile boundary of field values to be used in an aggregation operation.
     | Q3
@@ -177,6 +183,7 @@
 operationSpec Median = "median"
 operationSpec Min = "min"
 operationSpec Missing = "missing"
+operationSpec Product = "product"
 operationSpec Q1 = "q1"
 operationSpec Q3 = "q3"
 operationSpec Stderr = "stderr"
diff --git a/tests/AxisTests.hs b/tests/AxisTests.hs
--- a/tests/AxisTests.hs
+++ b/tests/AxisTests.hs
@@ -37,7 +37,10 @@
             , ("axisstyleempty", axisStyleEmpty)
             , ("axisstyleemptyx", axisStyleEmptyX)
             , ("axisstylex", axisStyleX)
+            , ("axisstylexastyle", axisStyleXAStyle)
             , ("axisstylexy", axisStyleXY)
+            , ("singleline", singleLine)
+            , ("multiline", multiLine)
             ]
 
 
@@ -106,17 +109,17 @@
   in toVegaLite vs
 
 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"
-                         ]
+plotCfg = [ AxisQuantitative AxXY [ DomainColor "orange"
+                                  , GridColor "seagreen"
+                                  , LabelFont "Comic Sans MS"
+                                  , LabelOffset 10
+                                  , TickOffset 10
+                                  ]
+          , AxisTemporal AxXY [ DomainColor "brown"
+                              , DomainDash [4, 2]
+                              , Grid False
+                              , LabelColor "purple"
+                              ]
           , PointStyle [ MStroke "black"
                        , MStrokeOpacity 0.4
                        , MStrokeWidth 1
@@ -305,6 +308,24 @@
                 ]
 
 
+-- check AStyle; should give same look as axisStyleX
+axisStyleXAStyle :: VegaLite
+axisStyleXAStyle =
+  let cfg = configure
+            . configuration (AxisNamedStyles [("x-style", [ AxDomainColor "orange"
+                                                          , AxGridColor "lightgreen"
+                                                          , AxLabelExpr xexpr ])])
+            . configuration (AxisX [AStyle ["x-style"]])
+
+      xexpr = "if (datum.value <= 100, 'low:' + datum.label, 'high:' + datum.label)"
+
+  in toVegaLite [ cfg []
+                , carData
+                , carEnc [] []
+                , mark Point []
+                ]
+
+
 axisStyleXY :: VegaLite
 axisStyleXY =
   let cfg = configure
@@ -324,4 +345,34 @@
                 , carData
                 , carEnc [AxStyle ["x-style"]] [AxStyle ["y-style"]]
                 , mark Point []
+                ]
+
+
+singleLine :: VegaLite
+singleLine =
+  let xOpts = [ AxLabelExpr "datum.label + ' horses'" ]
+      yOpts = [ AxLabelExpr "datum.label+' mpg'" ]
+
+  in toVegaLite [ carData
+                , carEnc xOpts yOpts
+                , mark Point []
+                ]
+
+
+multiLine :: VegaLite
+multiLine =
+  let xOpts = [ AxLabelExpr "datum.label + ' horses'"
+              , AxLabelLineHeight 22
+              , AxLabelFontSize 11
+              ]
+      yOpts = [ AxLabelExpr "datum.label+' mpg'"
+              , AxLabelFontSize 22 ]
+
+  in toVegaLite [ carData
+                , carEnc xOpts yOpts
+                , mark Point []
+                , configure
+                  . configuration (LineBreakStyle " ")
+                  . configuration (Axis [LabelLineHeight 20])
+                  $ []
                 ]
diff --git a/tests/ConfigTests.hs b/tests/ConfigTests.hs
--- a/tests/ConfigTests.hs
+++ b/tests/ConfigTests.hs
@@ -6,10 +6,6 @@
 --  - Padding has been removed as the resulting spec does not validate
 --    against v3.3.0
 --
---  - the vbTest output is not valid since the spec description says that
---    style can be a string or array-of-strings, but the type is only
---    string.
---
 
 module ConfigTests (testSpecs) where
 
@@ -38,6 +34,7 @@
             , ("titleCfg1", titleCfg1)
             , ("titleCfg2", titleCfg2)
             , ("titleCfg3", titleCfg3)
+            , ("breaklinecfg", breakLineCfg)
             ]
 
 
@@ -318,3 +315,22 @@
      ( [ cfg []
        , title "Car\nScatter" [ subtitle ]
        ] ++ titleOpts )
+
+
+breakLineCfg :: VegaLite
+breakLineCfg =
+  let dvals = dataFromColumns []
+               . dataColumn "x" (Numbers [5, 10, 15])
+               . dataColumn "y" (Numbers [10, 5, 30])
+               . dataColumn "l" (Strings ["xXx", "x x", "xxXxXxx"])
+
+      enc = encoding
+            . position X [PName "x", PmType Quantitative]
+            . position Y [PName "y", PmType Quantitative]
+            . text [TName "l", TmType Nominal]
+
+  in toVegaLite [ configure (configuration (LineBreakStyle "X") [])
+                , dvals []
+                , enc []
+                , mark Text []
+                ]
diff --git a/tests/FilterTests.hs b/tests/FilterTests.hs
new file mode 100644
--- /dev/null
+++ b/tests/FilterTests.hs
@@ -0,0 +1,85 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module FilterTests (testSpecs) where
+
+import Data.Function ((&))
+
+import Graphics.Vega.VegaLite
+
+import Prelude hiding (filter)
+
+testSpecs :: [(String, VegaLite)]
+testSpecs = [ ("datedate", dateDate)
+            , ("datedatell", dateDateLL)
+            , ("datedateul", dateDateUL)
+            , ("datenumber", dateNumber)
+            , ("datenumberll", dateNumberLL)
+            , ("datenumberul", dateNumberUL)
+            ]
+
+stockData :: Data
+stockData = dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
+
+goog :: [TransformSpec] -> PropertySpec
+goog = transform . filter (FExpr "datum.symbol === 'GOOG'")
+
+baseEnc :: [EncodingSpec] -> PropertySpec
+baseEnc = encoding
+          . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%m %Y" ] ]
+          . position Y [ PName "price", PmType Quantitative ]
+
+
+dateFilter :: Filter -> VegaLite
+dateFilter fexpr =
+  toVegaLite [ stockData
+             , goog
+               . filter fexpr
+               $ []
+             , width 400
+             , mark Line []
+             , baseEnc []
+             , configure
+               . configuration (Axis [DomainColor "#ddd", TickColor "#ddd"])
+               . configuration (LineBreakStyle " ")
+               $ []
+             ]
+
+  
+dateFilterNumbers :: Maybe Double -> Maybe Double -> VegaLite
+dateFilterNumbers mlo mhi =
+  let yearRange = FRange "date" frange
+                  & FilterOpTrans (MTimeUnit Year)
+                  & FCompose
+
+      frange = case (mlo, mhi) of
+                 (Just lo, Just hi) -> NumberRange lo hi
+                 (Just lo, Nothing) -> NumberRangeLL lo
+                 (Nothing, Just hi) -> NumberRangeUL hi
+                 _ -> error "Internal error"
+
+  in dateFilter yearRange
+
+
+dateFilterDates :: Maybe Int -> Maybe Int -> VegaLite
+dateFilterDates mlo mhi =
+  let yearRange = FRange "date" frange
+
+      frange = case (mlo, mhi) of
+                 (Just lo, Just hi) -> DateRange [DTYear lo] [DTYear hi]
+                 (Just lo, Nothing) -> DateRange [DTYear lo] []
+                 (Nothing, Just hi) -> DateRange [] [DTYear hi]
+                 _ -> error "Internal error"
+
+  in dateFilter yearRange
+
+
+dateDate, dateDateLL, dateDateUL :: VegaLite
+dateDate = dateFilterDates (Just 2006) (Just 2007)
+dateDateLL = dateFilterDates (Just 2006) Nothing
+dateDateUL = dateFilterDates Nothing (Just 2007)
+
+
+dateNumber, dateNumberLL, dateNumberUL :: VegaLite
+dateNumber = dateFilterNumbers (Just 2006) (Just 2007)
+dateNumberLL = dateFilterNumbers (Just 2006) Nothing
+dateNumberUL = dateFilterNumbers Nothing (Just 2007)
diff --git a/tests/Gallery/Facet.hs b/tests/Gallery/Facet.hs
--- a/tests/Gallery/Facet.hs
+++ b/tests/Gallery/Facet.hs
@@ -20,6 +20,7 @@
             , ("facet5", facet5)
             , ("facet6", facet6)
             , ("facet7", facet7)
+            , ("trellisareaseattle", trellisAreaSeattle)
             ]
 
 
@@ -214,3 +215,52 @@
                 . configuration (ViewStyle [ ViewNoStroke ])
     in
     toVegaLite [ des, width 300, height 50, cfg [], res [], dvals [], mark Area [], enc [] ]
+
+
+-- https://vega.github.io/vega-lite/examples/trellis_area_seattle.html
+--
+trellisAreaSeattle :: VegaLite
+trellisAreaSeattle =
+  let desc = description "Average temps in Seattle, by hour"
+
+      ylabels = "hours(datum.value) == 0 ? 'Midnight' : hours(datum.value) == 12 ? 'Noon' : timeFormat(datum.value, '%I:%M %p')"
+
+      plot = asSpec [ width 800
+                    , height 25
+                    , viewBackground [VBNoStroke]
+                    , mark Area []
+                    , encoding
+                      . position X [ PName "date"
+                                   , PmType Temporal
+                                   , PTitle "Month"
+                                   , PAxis [AxFormat "%b"]
+                                   ]
+                      . position Y [ PName "temp"
+                                   , PmType Quantitative
+                                   , PScale [SZero False]
+                                   , PAxis [AxNoTitle, AxLabels False, AxTicks False]
+                                   ]
+                      $ []
+                    ]
+
+  in toVegaLite [ desc
+                , title "Seattle Annual Temperatures" []
+                , dataFromUrl "https://vega.github.io/vega-lite/data/seattle-temps.csv" []
+                , transform
+                  (calculateAs "(hours(datum.date) + 18) % 24" "order" [])
+                , spacing 1  -- NOTE: can not specify this is just for row
+                , configure (configuration (Axis [Grid False, Domain False]) [])
+                , facet [ RowBy [ FName "date"
+                                , FmType Nominal
+                                , FTimeUnit Hours
+                                , FSort [ByFieldOp "order" Max] -- don't want an operation
+                                , FHeader [ HLabelAngle 0
+                                          , HLabelPadding 2
+                                          , HTitlePadding (-4)
+                                          , HLabelAlign AlignLeft
+                                          , HLabelExpr ylabels
+                                          ]
+                                ]
+                        ]
+                , specification plot
+                ]
diff --git a/tests/Gallery/Label.hs b/tests/Gallery/Label.hs
--- a/tests/Gallery/Label.hs
+++ b/tests/Gallery/Label.hs
@@ -755,33 +755,40 @@
 baselines :: VegaLite
 baselines =
   let dvals = dataFromColumns []
-              . dataColumn "x" (Numbers [ 10, 20 ])
-              . dataColumn "y" (Numbers [ 10, 20 ])
+              . dataColumn "x" (Numbers [ 5, 30 ])
+              . dataColumn "y" (Numbers [ 5, 30 ])
 
       ax t n = position t [ PName n
                           , PmType Quantitative
                           , PScale [ SNice (IsNice False)
-                                   , SDomain (DNumbers [5, 25])
+                                   , SDomain (DNumbers [-10, 40])
                                    ]
-                          , PAxis [ AxNoTitle ]
+                          , PAxis [ AxNoTitle
+                                  ]
                           ]
 
       enc = encoding
             . ax X "x"
             . ax Y "y"
-            . text [ TString "Xxgq" ]
+            . text [ TStrings ["Xxgq", "qTpP"] ]
 
       plot l a = asSpec [ enc [], title l [], mark Text [ MBaseline a ] ]
 
+      -- plots are ordered left to right, top to bottom
       plots = vlConcat [ plot "top" AlignTop
+                       , plot "line-top" AlignLineTop
                        , plot "middle" AlignMiddle
                        , plot "baseline" AlignBaseline
                        , plot "bottom" AlignBottom
+                       , plot "line-bottom" AlignLineBottom
                        ]
 
   in toVegaLite [ dvals []
                 , configure
-                  . configuration (MarkStyle [ MFontSize 20 ])
+                  . configuration (MarkStyle [ MFontSize 20
+                                             , MFontStyle "italic"
+                                             , MLineHeight 30 ])
+                  . configuration (TitleStyle [ TFont "Comic Sans MS" ])
                   $ []
                 , columns 2
                 , plots
diff --git a/tests/Gallery/Line.hs b/tests/Gallery/Line.hs
--- a/tests/Gallery/Line.hs
+++ b/tests/Gallery/Line.hs
@@ -11,6 +11,7 @@
 import Graphics.Vega.VegaLite
 
 import Prelude hiding (filter, lookup, repeat)
+import Data.Function ((&))
 
 
 testSpecs :: [(String, VegaLite)]
@@ -26,72 +27,51 @@
             , ("line10", line10)
             , ("line11", line11)
             , ("line12", line12)
+            , ("conditionalaxis", conditionalAxis)
             ]
 
 
-line1 :: VegaLite
-line1 =
-    let
-        des =
-            description "Google's stock price over time."
+stockData :: Data
+stockData = dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
 
-        trans =
-            transform . filter (FExpr "datum.symbol === 'GOOG'")
+goog :: [TransformSpec] -> PropertySpec
+goog = transform . filter (FExpr "datum.symbol === 'GOOG'")
 
-        enc =
-            encoding
-                . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%Y" ] ]
-                . position Y [ PName "price", PmType Quantitative ]
-    in
+baseEnc :: [EncodingSpec] -> PropertySpec
+baseEnc = encoding
+          . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%Y" ] ]
+          . position Y [ PName "price", PmType Quantitative ]
+
+
+line1 :: VegaLite
+line1 =
     toVegaLite
-        [ des
-        , dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
-        , trans []
+        [ description "Google's stock price over time."
+        , stockData
+        , goog []
         , mark Line []
-        , enc []
+        , baseEnc []
         ]
 
 
 line2 :: VegaLite
 line2 =
-    let
-        des =
-            description "Google's stock price over time with point markers."
-
-        trans =
-            transform . filter (FExpr "datum.symbol === 'GOOG'")
-
-        enc =
-            encoding
-                . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%Y" ] ]
-                . position Y [ PName "price", PmType Quantitative ]
-    in
     toVegaLite
-        [ des
-        , dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
-        , trans []
+        [ description "Google's stock price over time with point markers."
+        , stockData
+        , goog []
         , mark Line [ MColor "green", MPoint (PMMarker [ MColor "purple" ]) ]
-        , enc []
+        , baseEnc []
         ]
 
 
 line3 :: VegaLite
 line3 =
-    let
-        des =
-            description "Stock prices of 5 tech companies over time."
-
-        enc =
-            encoding
-                . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%Y" ] ]
-                . position Y [ PName "price", PmType Quantitative ]
-                . color [ MName "symbol", MmType Nominal ]
-    in
     toVegaLite
-        [ des
-        , dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
+        [ description "Stock prices of 5 tech companies over time."
+        , stockData
         , mark Line []
-        , enc []
+        , baseEnc (color [ MName "symbol", MmType Nominal ] [])
         ]
 
 
@@ -118,24 +98,12 @@
 
 line5 :: VegaLite
 line5 =
-    let
-        des =
-            description "Google's stock price over time (quantized as a step-chart)."
-
-        trans =
-            transform . filter (FExpr "datum.symbol === 'GOOG'")
-
-        enc =
-            encoding
-                . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%Y" ] ]
-                . position Y [ PName "price", PmType Quantitative ]
-    in
     toVegaLite
-        [ des
-        , dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
-        , trans []
+        [ description "Google's stock price over time (quantized as a step-chart)."
+        , stockData
+        , goog []
         , mark Line [ MInterpolate StepAfter ]
-        , enc []
+        , baseEnc []
         ]
 
 
@@ -145,20 +113,13 @@
         des =
             description "Google's stock price over time (smoothed with monotonic interpolation)."
 
-        trans =
-            transform . filter (FExpr "datum.symbol === 'GOOG'")
-
-        enc =
-            encoding
-                . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%Y" ] ]
-                . position Y [ PName "price", PmType Quantitative ]
     in
     toVegaLite
         [ des
-        , dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
-        , trans []
+        , stockData
+        , goog []
         , mark Line [ MInterpolate Monotone ]
-        , enc []
+        , baseEnc []
         ]
 
 
@@ -189,15 +150,13 @@
             description "Stock prices of five tech companies over time double encoding price with vertical position and line thickness."
 
         enc =
-            encoding
-                . position X [ PName "date", PmType Temporal, PAxis [ AxFormat "%Y" ] ]
-                . position Y [ PName "price", PmType Quantitative ]
-                . size [ MName "price", MmType Quantitative ]
-                . color [ MName "symbol", MmType Nominal ]
+            baseEnc
+              . size [ MName "price", MmType Quantitative ]
+              . color [ MName "symbol", MmType Nominal ]
     in
     toVegaLite
         [ des
-        , dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []
+        , stockData
         , mark Trail []
         , enc []
         ]
@@ -371,3 +330,49 @@
             asSpec [ encCos [], mark Line [ MStroke "firebrick" ] ]
     in
     toVegaLite [ des, width 300, height 150, dvals, trans [], layer [ specSin, specCos ] ]
+
+
+-- From https://vega.github.io/vega-lite/examples/line_conditional_axis.html
+-- added in Vega-Lite 4.6.0
+--
+conditionalAxis :: VegaLite
+conditionalAxis =
+  let enc = encoding
+            . position Y [PName "price", PmType Quantitative]
+            . position X [PName "date", PmType Temporal, PAxis axOpts]
+
+      axOpts = [ AxTickCount 8
+               , AxLabelAlign AlignLeft
+               , AxLabelExpr expr
+               , AxLabelOffset 4
+               , AxLabelPadding (-24)
+               , AxTickSize 30
+               , AxDataCondition
+                   cond
+                   (CAxGridDash [] [2, 2])
+               , AxDataCondition
+                   cond
+                   (CAxTickDash [] [2, 2])
+               ]
+
+      expr = "[timeFormat(datum.value, '%b'), timeFormat(datum.value, '%m') == '01' ? timeFormat(datum.value, '%Y') : '']"
+
+      cond = FEqual "value" (Number 1)
+             & FilterOpTrans (MTimeUnit Month)
+
+      yearRange = FRange "date" (NumberRange 2006 2007)
+                  & FilterOpTrans (MTimeUnit Year)
+                  & FCompose
+
+  in toVegaLite [ description "Line chart with conditional axis ticks, labels, and grid."
+                , stockData
+                , goog
+                  . filter yearRange
+                  $ []
+                , width 400
+                , mark Line []
+                , enc []
+                , configure
+                  . configuration (Axis [DomainColor "#ddd", TickColor "#ddd"])
+                  $ []
+                ]
diff --git a/tests/Gallery/Multi.hs b/tests/Gallery/Multi.hs
--- a/tests/Gallery/Multi.hs
+++ b/tests/Gallery/Multi.hs
@@ -19,6 +19,7 @@
             , ("multi6", multi6)
             , ("multi7", multi7)
             , ("multi8", multi8)
+            , ("selectandzoom", selectAndZoom)
             ]
 
 
@@ -493,3 +494,40 @@
       spec2 = asSpec [ width 963, height 100, enc2 [], mark Bar [] ]
 
   in toVegaLite [ dvals, trans [], vConcat [ spec1, spec2 ] ]
+
+
+-- interval selection in one plot to zoom in in second plot.
+--
+selectAndZoom :: VegaLite
+selectAndZoom =
+  let plot1 = asSpec [ encoding
+                       . position X [ PName "theta", PmType Quantitative, PAxis [] ]
+                       . position Y [ PName "y", PmType Quantitative, PAxis [] ]
+                       $ []
+                     , mark Line []
+                     , selection
+                       . select "brush" Interval [ Encodings [ChX, ChY]
+                                                 , SInitInterval (Just xr) (Just yr)
+                                                 ]
+                       $ []
+                     ]
+
+      xr = (Number 0.2, Number 6)
+      yr = (Number (-0.8), Number 0.8)
+
+      xscale = [ SDomain (DSelectionField "brush" "theta") ]
+      yscale = [ SDomain (DSelectionChannel "brush" ChY) ]
+
+      plot2 = asSpec [ encoding
+                       . position X [ PName "theta", PmType Quantitative, PScale xscale ]
+                       . position Y [ PName "y", PmType Quantitative, PScale yscale ]
+                       $ []
+                     , mark Circle []
+                     ]
+
+  in toVegaLite [ dataSequenceAs 0 6.28 0.1 "theta"
+                , transform
+                  . calculateAs "cos(datum.theta)" "y"
+                  $ []
+                , vConcat [plot1, plot2]
+                ]
diff --git a/tests/MarkTests.hs b/tests/MarkTests.hs
new file mode 100644
--- /dev/null
+++ b/tests/MarkTests.hs
@@ -0,0 +1,130 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+--
+-- random mark-related tests
+--
+
+module MarkTests (testSpecs) where
+
+import qualified Data.Text as T
+
+import Data.List (intercalate)
+
+#if !(MIN_VERSION_base(4, 12, 0))
+import Data.Monoid ((<>))
+#endif
+
+import Text.Printf (printf)
+
+import Graphics.Vega.VegaLite
+
+testSpecs :: [(String, VegaLite)]
+testSpecs = [("blendmode", blendMode)]
+
+
+-- How does blend-mode work (added in Vega-Lite 4.6.0)?
+-- This is based on
+-- https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode#Examples
+--
+
+blendData :: Data
+blendData =
+  dataFromColumns []
+  . dataColumn "x" (Numbers [0])
+  . dataColumn "y" (Numbers [0])
+  $ []
+
+
+-- rotate an ellipse about the origin; it would be better if I learned
+-- how to use the arc path segment
+--
+-- angle in degrees
+ellipse :: Double -> Symbol
+ellipse ang =
+  let rad = ang * pi / 180
+      cosRot = cos rad
+      sinRot = sin rad
+      
+      rmajor = 1.0
+      rminor = 0.3
+
+      p = printf "%.2f"
+            
+      -- could learn to use the Arc path segment, but just do it manually
+      pair t =
+        let x = rmajor * cos t * cosRot - rminor * sin t * sinRot
+            y = rmajor * cos t * sinRot + rminor * sin t * cosRot
+        in "L " <> p x <> " " <> p y
+
+      thetas = [0, 0.25 ..  2 * pi]
+      path = intercalate " " (map pair thetas)
+      
+  in SymPath (T.pack path)
+  
+
+-- Is there a better way to do this?
+blendMode :: VegaLite
+blendMode =
+  let ax t f = position t [ PName f
+                          , PmType Quantitative
+                          , PScale [SDomain (DNumbers [-5, 5])]
+                          ]
+
+      -- randomly trying to get similar results to the Mozilla page
+      props 0 = [GrX1 0.5, GrX2 0.5, GrY1 1, GrY2 0] 
+      props 1 = [GrX1 0.7, GrX2 0.3, GrY1 0.1, GrY2 1]
+      props _ = [GrX1 1, GrX2 0, GrY1 1, GrY2 0]
+      
+      gradient f =
+        let c | f == 0 = "rgb(0,255,0)"
+              | f == 1 = "rgb(255,0,0)"
+              | otherwise = "rgb(0,0,255)"
+              
+        in MFillGradient GrLinear [(0, "white"), (1, c)] (props f)
+
+      lyr bm f =
+        let a | f == 0 = 0
+              | f == 1 = 45
+              | otherwise = -45
+              
+        in asSpec [ mark Point [ MShape (ellipse a)
+                               , MBlend bm
+                               , gradient f
+                               ]
+                  ]
+
+      createLayer (bm, ttl) =
+        asSpec [ encoding . ax X "x" . ax Y "y" $ []
+               , layer (map (lyr bm) [0::Int .. 2])
+               , title ttl []
+               ]
+
+      layers = map createLayer [ (BMNormal, "Normal")
+                               , (BMMultiply, "Multiply")
+                               , (BMScreen, "Screen")
+                               , (BMOverlay, "Overlay")
+                               , (BMDarken, "Darken")
+                               , (BMLighten, "Lighten")
+                               , (BMColorDodge, "Color-Dodge")
+                               , (BMColorBurn, "Color-Burn")
+                               , (BMHardLight, "Hard-Light")
+                               , (BMSoftLight, "Soft-Light")
+                               , (BMDifference, "Difference")
+                               , (BMExclusion, "Exclusion")
+                               , (BMHue, "Hue")
+                               , (BMSaturation, "Saturation")
+                               , (BMColor, "Color")
+                               , (BMLuminosity, "Luminosity")
+                               ]
+      
+  in toVegaLite [ configure
+                  . configuration (Axis [Domain False, Labels False, Ticks False, NoTitle])
+                  . configuration (PointStyle [MOpacity 1, MSize 40000, MStroke ""])
+                  -- note the interesting background
+                  . configuration (BackgroundStyle "rgba(255,255,255,0)")
+                  $ []
+                , blendData
+                , columns 4
+                , vlConcat layers
+                ]
diff --git a/tests/Test.hs b/tests/Test.hs
--- a/tests/Test.hs
+++ b/tests/Test.hs
@@ -46,11 +46,13 @@
 import qualified DataTests as DT
 import qualified EncodingTests
 import qualified FillStrokeTests as FST
+import qualified FilterTests
 import qualified GeoTests as GT
 import qualified HyperlinkTests as HT
 import qualified ImageTests as ImT
 import qualified InteractionTests as IT
 import qualified LegendTests as LT
+import qualified MarkTests
 import qualified NullTests as NT
 import qualified PositionTests as PT
 import qualified ProjectionTests as PjT
@@ -119,11 +121,13 @@
   , toTests "Data" "data" DT.testSpecs
   , toTests "Encoding" "encoding" EncodingTests.testSpecs
   , toTests "FillStroke" "fillstroke" FST.testSpecs
+  , toTests "Filter" "filter" FilterTests.testSpecs
   , toTests "Geo" "geo" GT.testSpecs
   , toTests "Hyperlink" "hyperlink" HT.testSpecs
   , toTests "Image" "image" ImT.testSpecs
   , toTests "Interaction" "interaction" IT.testSpecs
   , toTests "Legend" "legend" LT.testSpecs
+  , toTests "Mark" "mark" MarkTests.testSpecs
   , toTests "Null" "null" NT.testSpecs
   , toTests "Position" "position" PT.testSpecs
   , toTests "Projection" "projection" PjT.testSpecs
diff --git a/tests/TransformTests.hs b/tests/TransformTests.hs
--- a/tests/TransformTests.hs
+++ b/tests/TransformTests.hs
@@ -35,6 +35,7 @@
             , ("weatherbymonth", weatherByMonth)
             , ("weatherbytwomonths", weatherByTwoMonths)
             , ("distances", distances)
+            , ("aggregates", aggregates)
             , ("weathermaxbins", weatherMaxBins)
             , ("windowplot", windowPlot)
             , ("joinaggregateplot", joinAggregatePlot)
@@ -380,6 +381,30 @@
                          , PAggregate Sum ]
 
   in toVegaLite [ dvals [], enc [], mark Bar [] ]
+
+
+aggregates :: VegaLite
+aggregates =
+  let dvals = dataFromColumns []
+              . dataColumn "xs" (Strings ["A", "A", "B", "A", "B", "B", "C", "C"])
+              . dataColumn "ys" (Numbers [1, 2, 2, 2, 3, 2, 4, 8])
+
+      enc op = encoding (position Y [ PName "ys"
+                                    , PAxis [AxTitle "Y"]
+                                    , PmType Quantitative
+                                    , PAggregate op ] [])
+
+      lyr1 = asSpec [ enc Sum, mark Bar [MStroke "black"] ]
+      lyr2 = asSpec [ enc Product, mark Line [MColor "brown"] ]
+      lyr3 = asSpec [ enc Max, mark Point [MColor "orange"] ]
+      lyr4 = asSpec [ enc Distinct, mark Square [MColor "cyan"] ]
+
+      axOpts = PAxis [AxTitle "X", AxLabelAngle 0]
+
+  in toVegaLite [ dvals []
+                , encoding (position X [PName "xs", axOpts, PmType Ordinal] [])
+                , layer [lyr1, lyr2, lyr3, lyr4]
+                ]
 
 
 activityData :: Data
diff --git a/tests/specs/axis/axisstylexastyle.vl b/tests/specs/axis/axisstylexastyle.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/axisstylexastyle.vl
@@ -0,0 +1,34 @@
+{
+    "config": {
+        "style": {
+            "x-style": {
+                "domainColor": "orange",
+                "labelExpr": "if (datum.value <= 100, 'low:' + datum.label, 'high:' + datum.label)",
+                "gridColor": "lightgreen"
+            }
+        },
+        "axisX": {
+            "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"
+        },
+        "y": {
+            "field": "Miles_per_Gallon",
+            "type": "quantitative"
+        }
+    }
+}
diff --git a/tests/specs/axis/multiline.vl b/tests/specs/axis/multiline.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/multiline.vl
@@ -0,0 +1,37 @@
+{
+    "config": {
+        "axis": {
+            "labelLineHeight": 20
+        },
+        "lineBreak": " "
+    },
+    "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": {
+                "labelExpr": "datum.label + ' horses'",
+                "labelLineHeight": 22,
+                "labelFontSize": 11
+            }
+        },
+        "y": {
+            "field": "Miles_per_Gallon",
+            "type": "quantitative",
+            "axis": {
+                "labelExpr": "datum.label+' mpg'",
+                "labelFontSize": 22
+            }
+        }
+    }
+}
diff --git a/tests/specs/axis/singleline.vl b/tests/specs/axis/singleline.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/axis/singleline.vl
@@ -0,0 +1,28 @@
+{
+    "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": {
+                "labelExpr": "datum.label + ' horses'"
+            }
+        },
+        "y": {
+            "field": "Miles_per_Gallon",
+            "type": "quantitative",
+            "axis": {
+                "labelExpr": "datum.label+' mpg'"
+            }
+        }
+    }
+}
diff --git a/tests/specs/config/breaklinecfg.vl b/tests/specs/config/breaklinecfg.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/config/breaklinecfg.vl
@@ -0,0 +1,40 @@
+{
+    "config": {
+        "lineBreak": "X"
+    },
+    "mark": "text",
+    "data": {
+        "values": [
+            {
+                "l": "xXx",
+                "x": 5,
+                "y": 10
+            },
+            {
+                "l": "x x",
+                "x": 10,
+                "y": 5
+            },
+            {
+                "l": "xxXxXxx",
+                "x": 15,
+                "y": 30
+            }
+        ]
+    },
+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
+    "encoding": {
+        "text": {
+            "field": "l",
+            "type": "nominal"
+        },
+        "x": {
+            "field": "x",
+            "type": "quantitative"
+        },
+        "y": {
+            "field": "y",
+            "type": "quantitative"
+        }
+    }
+}
diff --git a/tests/specs/gallery/facet/trellisareaseattle.vl b/tests/specs/gallery/facet/trellisareaseattle.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/facet/trellisareaseattle.vl
@@ -0,0 +1,69 @@
+{
+    "transform": [
+        {
+            "as": "order",
+            "calculate": "(hours(datum.date) + 18) % 24"
+        }
+    ],
+    "config": {
+        "axis": {
+            "domain": false,
+            "grid": false
+        }
+    },
+    "data": {
+        "url": "https://vega.github.io/vega-lite/data/seattle-temps.csv"
+    },
+    "spec": {
+        "height": 25,
+        "mark": "area",
+        "width": 800,
+        "view": {
+            "stroke": null
+        },
+        "encoding": {
+            "x": {
+                "field": "date",
+                "title": "Month",
+                "type": "temporal",
+                "axis": {
+                    "format": "%b"
+                }
+            },
+            "y": {
+                "field": "temp",
+                "scale": {
+                    "zero": false
+                },
+                "type": "quantitative",
+                "axis": {
+                    "labels": false,
+                    "title": null,
+                    "ticks": false
+                }
+            }
+        }
+    },
+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
+    "facet": {
+        "row": {
+            "field": "date",
+            "timeUnit": "hours",
+            "header": {
+                "labelAngle": 0,
+                "labelExpr": "hours(datum.value) == 0 ? 'Midnight' : hours(datum.value) == 12 ? 'Noon' : timeFormat(datum.value, '%I:%M %p')",
+                "titlePadding": -4,
+                "labelPadding": 2,
+                "labelAlign": "left"
+            },
+            "sort": {
+                "op": "max",
+                "field": "order"
+            },
+            "type": "nominal"
+        }
+    },
+    "title": "Seattle Annual Temperatures",
+    "description": "Average temps in Seattle, by hour",
+    "spacing": 1
+}
diff --git a/tests/specs/gallery/label/baselines.vl b/tests/specs/gallery/label/baselines.vl
--- a/tests/specs/gallery/label/baselines.vl
+++ b/tests/specs/gallery/label/baselines.vl
@@ -1,18 +1,23 @@
 {
     "config": {
         "mark": {
-            "fontSize": 20
+            "fontStyle": "italic",
+            "fontSize": 20,
+            "lineHeight": 30
+        },
+        "title": {
+            "font": "Comic Sans MS"
         }
     },
     "data": {
         "values": [
             {
-                "x": 10,
-                "y": 10
+                "x": 5,
+                "y": 5
             },
             {
-                "x": 20,
-                "y": 20
+                "x": 30,
+                "y": 30
             }
         ]
     },
@@ -25,14 +30,17 @@
             "title": "top",
             "encoding": {
                 "text": {
-                    "value": "Xxgq"
+                    "value": [
+                        "Xxgq",
+                        "qTpP"
+                    ]
                 },
                 "x": {
                     "field": "x",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
@@ -45,8 +53,8 @@
                     "field": "y",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
@@ -60,19 +68,65 @@
         {
             "mark": {
                 "type": "text",
+                "baseline": "line-top"
+            },
+            "title": "line-top",
+            "encoding": {
+                "text": {
+                    "value": [
+                        "Xxgq",
+                        "qTpP"
+                    ]
+                },
+                "x": {
+                    "field": "x",
+                    "scale": {
+                        "domain": [
+                            -10,
+                            40
+                        ],
+                        "nice": false
+                    },
+                    "type": "quantitative",
+                    "axis": {
+                        "title": null
+                    }
+                },
+                "y": {
+                    "field": "y",
+                    "scale": {
+                        "domain": [
+                            -10,
+                            40
+                        ],
+                        "nice": false
+                    },
+                    "type": "quantitative",
+                    "axis": {
+                        "title": null
+                    }
+                }
+            }
+        },
+        {
+            "mark": {
+                "type": "text",
                 "baseline": "middle"
             },
             "title": "middle",
             "encoding": {
                 "text": {
-                    "value": "Xxgq"
+                    "value": [
+                        "Xxgq",
+                        "qTpP"
+                    ]
                 },
                 "x": {
                     "field": "x",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
@@ -85,8 +139,8 @@
                     "field": "y",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
@@ -105,14 +159,17 @@
             "title": "baseline",
             "encoding": {
                 "text": {
-                    "value": "Xxgq"
+                    "value": [
+                        "Xxgq",
+                        "qTpP"
+                    ]
                 },
                 "x": {
                     "field": "x",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
@@ -125,8 +182,8 @@
                     "field": "y",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
@@ -145,14 +202,17 @@
             "title": "bottom",
             "encoding": {
                 "text": {
-                    "value": "Xxgq"
+                    "value": [
+                        "Xxgq",
+                        "qTpP"
+                    ]
                 },
                 "x": {
                     "field": "x",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
@@ -165,8 +225,51 @@
                     "field": "y",
                     "scale": {
                         "domain": [
-                            5,
-                            25
+                            -10,
+                            40
+                        ],
+                        "nice": false
+                    },
+                    "type": "quantitative",
+                    "axis": {
+                        "title": null
+                    }
+                }
+            }
+        },
+        {
+            "mark": {
+                "type": "text",
+                "baseline": "line-bottom"
+            },
+            "title": "line-bottom",
+            "encoding": {
+                "text": {
+                    "value": [
+                        "Xxgq",
+                        "qTpP"
+                    ]
+                },
+                "x": {
+                    "field": "x",
+                    "scale": {
+                        "domain": [
+                            -10,
+                            40
+                        ],
+                        "nice": false
+                    },
+                    "type": "quantitative",
+                    "axis": {
+                        "title": null
+                    }
+                },
+                "y": {
+                    "field": "y",
+                    "scale": {
+                        "domain": [
+                            -10,
+                            40
                         ],
                         "nice": false
                     },
diff --git a/tests/specs/gallery/line/conditionalaxis.vl b/tests/specs/gallery/line/conditionalaxis.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/line/conditionalaxis.vl
@@ -0,0 +1,76 @@
+{
+    "transform": [
+        {
+            "filter": "datum.symbol === 'GOOG'"
+        },
+        {
+            "filter": {
+                "field": "date",
+                "timeUnit": "year",
+                "range": [
+                    2006,
+                    2007
+                ]
+            }
+        }
+    ],
+    "config": {
+        "axis": {
+            "domainColor": "#ddd",
+            "tickColor": "#ddd"
+        }
+    },
+    "mark": "line",
+    "data": {
+        "url": "https://vega.github.io/vega-lite/data/stocks.csv"
+    },
+    "width": 400,
+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
+    "encoding": {
+        "x": {
+            "field": "date",
+            "type": "temporal",
+            "axis": {
+                "tickSize": 30,
+                "labelOffset": 4,
+                "tickDash": {
+                    "value": [
+                        2,
+                        2
+                    ],
+                    "condition": {
+                        "value": [],
+                        "test": {
+                            "equal": 1,
+                            "field": "value",
+                            "timeUnit": "month"
+                        }
+                    }
+                },
+                "tickCount": 8,
+                "gridDash": {
+                    "value": [
+                        2,
+                        2
+                    ],
+                    "condition": {
+                        "value": [],
+                        "test": {
+                            "equal": 1,
+                            "field": "value",
+                            "timeUnit": "month"
+                        }
+                    }
+                },
+                "labelExpr": "[timeFormat(datum.value, '%b'), timeFormat(datum.value, '%m') == '01' ? timeFormat(datum.value, '%Y') : '']",
+                "labelPadding": -24,
+                "labelAlign": "left"
+            }
+        },
+        "y": {
+            "field": "price",
+            "type": "quantitative"
+        }
+    },
+    "description": "Line chart with conditional axis ticks, labels, and grid."
+}
diff --git a/tests/specs/gallery/multi/selectandzoom.vl b/tests/specs/gallery/multi/selectandzoom.vl
new file mode 100644
--- /dev/null
+++ b/tests/specs/gallery/multi/selectandzoom.vl
@@ -0,0 +1,78 @@
+{
+    "transform": [
+        {
+            "as": "y",
+            "calculate": "cos(datum.theta)"
+        }
+    ],
+    "data": {
+        "sequence": {
+            "as": "theta",
+            "start": 0,
+            "step": 0.1,
+            "stop": 6.28
+        }
+    },
+    "vconcat": [
+        {
+            "mark": "line",
+            "selection": {
+                "brush": {
+                    "init": {
+                        "x": [
+                            0.2,
+                            6
+                        ],
+                        "y": [
+                            -0.8,
+                            0.8
+                        ]
+                    },
+                    "encodings": [
+                        "x",
+                        "y"
+                    ],
+                    "type": "interval"
+                }
+            },
+            "encoding": {
+                "x": {
+                    "field": "theta",
+                    "type": "quantitative",
+                    "axis": null
+                },
+                "y": {
+                    "field": "y",
+                    "type": "quantitative",
+                    "axis": null
+                }
+            }
+        },
+        {
+            "mark": "circle",
+            "encoding": {
+                "x": {
+                    "field": "theta",
+                    "scale": {
+                        "domain": {
+                            "field": "theta",
+                            "selection": "brush"
+                        }
+                    },
+                    "type": "quantitative"
+                },
+                "y": {
+                    "field": "y",
+                    "scale": {
+                        "domain": {
+                            "selection": "brush",
+                            "encoding": "y"
+                        }
+                    },
+                    "type": "quantitative"
+                }
+            }
+        }
+    ],
+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json"
+}
diff --git a/tools/GetBetelgeuse.hs b/tools/GetBetelgeuse.hs
new file mode 100644
--- /dev/null
+++ b/tools/GetBetelgeuse.hs
@@ -0,0 +1,141 @@
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+{-
+
+Grab Betelgeuse data from the AAVSO site. This is based on
+code in https://github.com/hippke/betelbot which is
+used to generate the tweets from https://twitter.com/betelbot
+
+The idea is to download a bunch of Vis-band observations
+and grab the data from the HTML, convert to a very-simple
+JSON format and write to the screen. There is limited
+error checking.
+
+-}
+
+import qualified Data.ByteString.Lazy as L
+import qualified Data.ByteString.Lazy.Char8 as L8
+import qualified Data.Text as T
+import qualified Network.HTTP.Conduit as NHC
+
+import Data.Aeson (ToJSON(..), encode, defaultOptions, genericToEncoding)
+
+import Data.List (sortBy)
+import Data.Function (on)
+import Data.Maybe (fromMaybe, mapMaybe)
+import Data.Text.Encoding (decodeUtf8)
+
+import GHC.Generics
+
+import Text.HTML.TagSoup (Tag(..)
+                         , isTagOpenName
+                         , parseTags
+                         , partitions)
+import Text.Read (readMaybe)
+
+import Numeric.Natural (Natural)
+
+
+-- | The given page of results from AAVSO for Betelgeuse
+--
+--   When ran there were ~3900 results, so at 200 per page that's
+--   20 pages
+--
+pageURL :: Natural -> String
+pageURL p = "https://www.aavso.org/apps/webobs/results/?start=2017-06-01&num_results=200&obs_types=vis+ccd&star=betelgeuse&page=" <> show p
+
+nPages :: Natural
+nPages = 20
+
+
+-- | Return the given page.
+--
+getPage :: Natural -> IO T.Text
+getPage p = decodeUtf8 . L.toStrict <$> NHC.simpleHttp (pageURL p)
+
+
+data Row = Row { jd :: Double
+               , date :: T.Text
+               , magnitude :: Double
+               , magErr :: Maybe Double
+               , filterName :: T.Text
+               , observer :: T.Text
+               } deriving (Generic, Show)
+
+instance ToJSON Row where
+    toEncoding = genericToEncoding defaultOptions
+
+-- Extract rows
+--
+-- The data structure is regular, but complicated. I am going
+-- to ignore the "extra" data for each observation.
+--
+extractRows :: [Tag T.Text] -> [Row]
+extractRows tgs =
+  let rows = partitions (isTagOpenName "tr") tgs
+  in mapMaybe extractRow rows 
+
+
+isObs :: [(T.Text, T.Text)] -> Bool
+isObs xs =
+  let hasObs cls = "obs" `elem` T.splitOn " " cls
+      act = hasObs <$> lookup "class" xs
+  in fromMaybe False act
+
+  
+-- Is this a row we care about? The choice is made by
+-- only looking for rows with a class name of 'obs'.
+--
+extractRow :: [Tag T.Text] -> Maybe Row
+extractRow (TagOpen "tr" attrs : ts) | isObs attrs = toRow ts
+extractRow _ = Nothing
+  
+
+-- extract the text contents of the td element; highly specialised
+-- to this use case
+getText :: [Tag T.Text] -> T.Text
+getText (TagText txt:_) = txt
+getText (_:ts) = getText ts
+getText [] = error "unexpected data"
+
+
+-- probably not enough data checks
+toRow :: [Tag T.Text] -> Maybe Row
+toRow tgs =
+  let tds = partitions (isTagOpenName "td") tgs
+      jdTag = getText (tds !! 2)
+      dateTag = getText (tds !! 3)
+      magTag = getText (tds !! 4)
+      magETag = getText (tds !! 5)
+      filterTag = getText (tds !! 6)
+      obsTag = getText (tds !! 7)
+
+      magE = readMaybe (T.unpack magETag)
+
+  in if length tds /= 9
+     then Nothing
+     else Row <$> readMaybe (T.unpack jdTag)
+              <*> pure dateTag
+              <*> readMaybe (T.unpack magTag)
+              <*> pure magE
+              <*> pure filterTag
+              <*> pure obsTag
+
+
+processPage :: T.Text -> [Row]
+processPage = extractRows . parseTags
+
+
+main :: IO ()
+main = do
+  rs <- mapM (fmap processPage . getPage) [1..nPages]
+
+  -- assuming no chance of getting repeated rows from this query
+  let rows = concat rs
+      srows = sortBy (compare `on` jd) rows
+
+      js = encode srows
+
+  L8.putStrLn js
+  
diff --git a/tools/PlayTutorial.hs b/tools/PlayTutorial.hs
--- a/tools/PlayTutorial.hs
+++ b/tools/PlayTutorial.hs
@@ -57,34 +57,110 @@
 import System.FilePath ((</>), FilePath)
 import System.IO (hPutStrLn, stderr)
 
+import Prelude hiding (filter)
+
 -- Could use TH to get at the tutorials, but for now hard code the names.
 
 -- The intro visualization used in the API documentation (not in
 -- the tutorial).
 --
-vl1 :: VegaLite
-vl1 =
-  let desc = "A very exciting bar chart"
+-- How does Betelgeuse vary with time?
+--
+betelgeuse :: VegaLite
+betelgeuse =
+  let desc = "How has Betelgeuse's brightness varied, based on data collated by AAVSO (https://www.aavso.org/). You should also look at https://twitter.com/betelbot and https://github.com/hippke/betelbot. It was all the rage on social media at the start of 2020."
 
-      dat = dataFromRows [Parse [("start", FoDate "%Y-%m-%d")]]
-            . dataRow [("start", Str "2011-03-25"), ("count", Number 23)]
-            . dataRow [("start", Str "2011-04-02"), ("count", Number 45)]
-            . dataRow [("start", Str "2011-04-12"), ("count", Number 3)]
+      titleStr = "Betelegeuse's magnitude measurements, collated by AAVSO"
 
-      barOpts = [MOpacity 0.4, MColor "teal"]
+      -- height and width of individual plots
+      w = width 600
+      h = height 150
 
-      enc = encoding
-            . position X [PName "start", PmType Temporal, PAxis [AxTitle "Inception date"]]
-            . position Y [PName "count", PmType Quantitative]
+      pos1Opts fld ttl = [PName fld, PmType Quantitative, PAxis [AxTitle ttl]]
+      x1Opts = pos1Opts "days" "Days since January 1, 2020"
+      y1Opts = pos1Opts "magnitude" "Magnitude" ++ [PSort [Descending], yRange]
+      yRange = PScale [SDomain (DNumbers [-1, 3])]
 
-  in toVegaLite [description desc, background "white"
-                , dat [], mark Bar barOpts, enc []]
+      filtOpts = [MName "filterName", MmType Nominal]
+      filtEnc = color (MLegend [ LTitle "Filter", LTitleFontSize 16, LLabelFontSize 14 ] : filtOpts)
+                . shape filtOpts
 
+      circle = mark Point [ MOpacity 0.5, MFilled False ]
 
+      encOverview = encoding
+                    . position X x1Opts
+                    . position Y y1Opts
+                    . filtEnc
+
+      selName = "brush"
+      pos2Opts fld = [PName fld, PmType Quantitative, PAxis [AxNoTitle],
+                     PScale [SDomain (DSelectionField selName fld)]]
+      x2Opts = pos2Opts "days"
+      y2Opts = pos2Opts "magnitude" ++ [PSort [Descending]]
+
+      encDetail = encoding
+                  . position X x2Opts
+                  . position Y y2Opts
+                  . filtEnc
+
+      xlim = (Number (-220), Number 100)
+      ylim = (Number (-0.5), Number 2.5)
+      overview = asSpec [ w
+                        , h
+                        , encOverview []
+                        , selection
+                          . select selName Interval [ Encodings [ChX, ChY]
+                                                    , SInitInterval (Just xlim) (Just ylim)
+                                                    ]
+                          $ []
+                        , circle
+                        ]
+
+      detailPlot = asSpec [ w
+                          , h
+                          , encDetail []
+                          , circle
+                          ]
+
+      headerOpts = [ HLabelFontSize 16
+                   , HLabelAlign AlignRight
+                   , HLabelAnchor AEnd
+                   , HLabelPadding (-24)
+                   , HNoTitle
+                   , HLabelExpr "'Filter: ' + datum.label"
+                   ]
+
+      details = asSpec [ columns 1
+                       , facetFlow [ FName "filterName"
+                                   , FmType Nominal
+                                   , FHeader headerOpts
+                                   ]
+                       , spacing 10
+                       , specification detailPlot
+                       ]
+
+  in toVegaLite [ description desc
+                , title titleStr [ TFontSize 18 ]
+                , dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/betelgeuse-2020-03-19.json" []
+                , transform
+                  -- concentrate on the two filters with a reasonable number of points
+                  . filter (FExpr "datum.filterName[0] === 'V'")
+                  -- remove some "outliers"
+                  . filter (FExpr "datum.magnitude < 4")
+                  -- subtract Jan 1 2020 (start of day, hence the .0 rather than .5)
+                  . calculateAs "datum.jd - 2458849.0" "days"
+                  $ []
+                , vConcat [overview, details]
+                , configure
+                  . configuration (Axis [ TitleFontWeight Normal, TitleFontSize 16, LabelFontSize 14 ])
+                  $ []
+                ]
+
+
 -- Associate a name with each visualization
 --
 vl :: [(String, VegaLite)]
-vl = [ ("api-vl1", vl1)
+vl = [ ("api-betelgeuse", betelgeuse)
      , ("stripplot", VL.stripPlot)
      , ("stripplotwithbackground", VL.stripPlotWithBackground)
      , ("stripploty", VL.stripPlotY)
