packages feed

hvega 0.4.1.2 → 0.5.0.0

raw patch · 579 files changed

+30394/−14911 lines, 579 filesdep −vectorbinary-addedPVP ok

version bump matches the API change (PVP)

Dependencies removed: vector

API changes (from Hackage documentation)

- Graphics.Vega.VegaLite: LeShortTimeLabels :: Bool -> LegendConfig
- Graphics.Vega.VegaLite: MShortTimeLabels :: Bool -> MarkProperty
- Graphics.Vega.VegaLite: RemoveInvalid :: Bool -> ConfigurationProperty
- Graphics.Vega.VegaLite: SCRangeStep :: Maybe Double -> ScaleConfig
- Graphics.Vega.VegaLite: SCTextXRangeStep :: Double -> ScaleConfig
- Graphics.Vega.VegaLite: SRangeStep :: Maybe Double -> ScaleProperty
- Graphics.Vega.VegaLite: ShortTimeLabels :: Bool -> AxisConfig
- Graphics.Vega.VegaLite: Stack :: StackOffset -> ConfigurationProperty
- Graphics.Vega.VegaLite: combineSpecs :: [LabelledSpec] -> VLSpec
- Graphics.Vega.VegaLite: type BuildLabelledSpecs = [LabelledSpec] -> [LabelledSpec]
+ Graphics.Vega.Tutorials.VegaLite: choroplethLookupFromGeo :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: choroplethLookupToGeo :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: clusterCenters :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: compareCounts :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: concatenatedSkyPlot :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: densityMultiples :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: densityParallax :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: densityParallaxGrouped :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: duplicateAxis :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: layeredCount :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: legendSelection :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: loessExample :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: parallaxView :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: regressionExample :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: skyPlotAitoff :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: skyPlotWithGraticules :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: starCount :: VegaLite
+ Graphics.Vega.Tutorials.VegaLite: starCount2 :: VegaLite
+ Graphics.Vega.VegaLite: AFitX :: Autosize
+ Graphics.Vega.VegaLite: AFitY :: Autosize
+ Graphics.Vega.VegaLite: AxDataCondition :: BooleanOp -> ConditionalAxisProperty -> AxisProperty
+ Graphics.Vega.VegaLite: AxLabelExpr :: VegaExpr -> AxisProperty
+ Graphics.Vega.VegaLite: AxTickBand :: BandAlign -> AxisProperty
+ Graphics.Vega.VegaLite: AxTitleLineHeight :: Double -> AxisProperty
+ Graphics.Vega.VegaLite: AxTranslateOffset :: Double -> AxisProperty
+ Graphics.Vega.VegaLite: BCenter :: BandAlign
+ Graphics.Vega.VegaLite: BExtent :: BandAlign
+ Graphics.Vega.VegaLite: BLChannel :: Channel -> BindLegendProperty
+ Graphics.Vega.VegaLite: BLChannelEvent :: Channel -> Text -> BindLegendProperty
+ Graphics.Vega.VegaLite: BLField :: FieldName -> BindLegendProperty
+ Graphics.Vega.VegaLite: BLFieldEvent :: FieldName -> Text -> BindLegendProperty
+ Graphics.Vega.VegaLite: BindLegend :: BindLegendProperty -> SelectionProperty
+ Graphics.Vega.VegaLite: CAxGridColor :: Color -> Color -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxGridDash :: DashStyle -> DashStyle -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxGridDashOffset :: DashOffset -> DashOffset -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxGridOpacity :: Opacity -> Opacity -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxGridWidth :: Double -> Double -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelAlign :: HAlign -> HAlign -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelBaseline :: VAlign -> VAlign -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelColor :: Color -> Color -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelFont :: Text -> Text -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelFontSize :: Double -> Double -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelFontStyle :: Text -> Text -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelFontWeight :: FontWeight -> FontWeight -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxLabelOpacity :: Opacity -> Opacity -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxTickColor :: Text -> Text -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxTickDash :: DashStyle -> DashStyle -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxTickDashOffset :: DashOffset -> DashOffset -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxTickOpacity :: Opacity -> Opacity -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: CAxTickWidth :: Double -> Double -> ConditionalAxisProperty
+ Graphics.Vega.VegaLite: DTDayNum :: Int -> DateTime
+ Graphics.Vega.VegaLite: DTMonthNum :: Int -> DateTime
+ Graphics.Vega.VegaLite: DnAs :: FieldName -> FieldName -> DensityProperty
+ Graphics.Vega.VegaLite: DnBandwidth :: Double -> DensityProperty
+ Graphics.Vega.VegaLite: DnCounts :: Bool -> DensityProperty
+ Graphics.Vega.VegaLite: DnCumulative :: Bool -> DensityProperty
+ Graphics.Vega.VegaLite: DnExtent :: Double -> Double -> DensityProperty
+ Graphics.Vega.VegaLite: DnGroupBy :: [FieldName] -> DensityProperty
+ Graphics.Vega.VegaLite: DnMaxSteps :: Natural -> DensityProperty
+ Graphics.Vega.VegaLite: DnMinSteps :: Natural -> DensityProperty
+ Graphics.Vega.VegaLite: DnSteps :: Natural -> DensityProperty
+ Graphics.Vega.VegaLite: EqualEarth :: Projection
+ Graphics.Vega.VegaLite: GrLinear :: ColorGradient
+ Graphics.Vega.VegaLite: GrR1 :: GradientCoord -> GradientProperty
+ Graphics.Vega.VegaLite: GrR2 :: GradientCoord -> GradientProperty
+ Graphics.Vega.VegaLite: GrRadial :: ColorGradient
+ Graphics.Vega.VegaLite: GrX1 :: GradientCoord -> GradientProperty
+ Graphics.Vega.VegaLite: GrX2 :: GradientCoord -> GradientProperty
+ Graphics.Vega.VegaLite: GrY1 :: GradientCoord -> GradientProperty
+ Graphics.Vega.VegaLite: GrY2 :: GradientCoord -> GradientProperty
+ Graphics.Vega.VegaLite: Image :: Mark
+ Graphics.Vega.VegaLite: LTR :: TextDirection
+ Graphics.Vega.VegaLite: LsAs :: FieldName -> FieldName -> LoessProperty
+ Graphics.Vega.VegaLite: LsBandwidth :: Double -> LoessProperty
+ Graphics.Vega.VegaLite: LsGroupBy :: [FieldName] -> LoessProperty
+ Graphics.Vega.VegaLite: LuAs :: FieldName -> LookupFields
+ Graphics.Vega.VegaLite: LuAsWithDefault :: FieldName -> Text -> LookupFields
+ Graphics.Vega.VegaLite: LuFieldAs :: [(FieldName, FieldName)] -> LookupFields
+ Graphics.Vega.VegaLite: LuFields :: [FieldName] -> LookupFields
+ Graphics.Vega.VegaLite: LuFieldsAsWithDefault :: [(FieldName, FieldName)] -> Text -> LookupFields
+ Graphics.Vega.VegaLite: LuFieldsWithDefault :: [FieldName] -> Text -> LookupFields
+ Graphics.Vega.VegaLite: MAspect :: Bool -> MarkProperty
+ Graphics.Vega.VegaLite: MColorGradient :: ColorGradient -> GradientStops -> [GradientProperty] -> MarkProperty
+ Graphics.Vega.VegaLite: MCornerRadius :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MCornerRadiusBL :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MCornerRadiusBR :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MCornerRadiusTL :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MCornerRadiusTR :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MDir :: TextDirection -> MarkProperty
+ Graphics.Vega.VegaLite: MEllipsis :: Text -> MarkProperty
+ Graphics.Vega.VegaLite: MFillGradient :: ColorGradient -> GradientStops -> [GradientProperty] -> MarkProperty
+ Graphics.Vega.VegaLite: MLimit :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MLineBreak :: Text -> MarkProperty
+ Graphics.Vega.VegaLite: MLineHeight :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MRemoveInvalid :: Bool -> MarkProperty
+ Graphics.Vega.VegaLite: MStrokeGradient :: ColorGradient -> GradientStops -> [GradientProperty] -> MarkProperty
+ Graphics.Vega.VegaLite: MTimeUnitBand :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MTimeUnitBandPosition :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: NaturalEarth1 :: Projection
+ Graphics.Vega.VegaLite: PBand :: Double -> PositionChannel
+ Graphics.Vega.VegaLite: PiGroupBy :: [FieldName] -> PivotProperty
+ Graphics.Vega.VegaLite: PiLimit :: Natural -> PivotProperty
+ Graphics.Vega.VegaLite: PiOp :: Operation -> PivotProperty
+ Graphics.Vega.VegaLite: QtAs :: FieldName -> FieldName -> QuantileProperty
+ Graphics.Vega.VegaLite: QtGroupBy :: [FieldName] -> QuantileProperty
+ Graphics.Vega.VegaLite: QtProbs :: [Double] -> QuantileProperty
+ Graphics.Vega.VegaLite: QtStep :: Double -> QuantileProperty
+ Graphics.Vega.VegaLite: RTL :: TextDirection
+ Graphics.Vega.VegaLite: RgAs :: FieldName -> FieldName -> RegressionProperty
+ Graphics.Vega.VegaLite: RgExp :: RegressionMethod
+ Graphics.Vega.VegaLite: RgExtent :: Double -> Double -> RegressionProperty
+ Graphics.Vega.VegaLite: RgGroupBy :: [FieldName] -> RegressionProperty
+ Graphics.Vega.VegaLite: RgLinear :: RegressionMethod
+ Graphics.Vega.VegaLite: RgLog :: RegressionMethod
+ Graphics.Vega.VegaLite: RgMethod :: RegressionMethod -> RegressionProperty
+ Graphics.Vega.VegaLite: RgOrder :: Natural -> RegressionProperty
+ Graphics.Vega.VegaLite: RgParams :: Bool -> RegressionProperty
+ Graphics.Vega.VegaLite: RgPoly :: RegressionMethod
+ Graphics.Vega.VegaLite: RgPow :: RegressionMethod
+ Graphics.Vega.VegaLite: RgQuad :: RegressionMethod
+ Graphics.Vega.VegaLite: SelectionExtent :: SelectionLabel -> BinProperty
+ Graphics.Vega.VegaLite: TAlign :: HAlign -> TitleConfig
+ Graphics.Vega.VegaLite: TLineHeight :: Double -> TitleConfig
+ Graphics.Vega.VegaLite: TString :: Text -> TextChannel
+ Graphics.Vega.VegaLite: TSubtitle :: Text -> TitleConfig
+ Graphics.Vega.VegaLite: TSubtitleColor :: Color -> TitleConfig
+ Graphics.Vega.VegaLite: TSubtitleFont :: Text -> TitleConfig
+ Graphics.Vega.VegaLite: TSubtitleFontSize :: Double -> TitleConfig
+ Graphics.Vega.VegaLite: TSubtitleFontStyle :: Text -> TitleConfig
+ Graphics.Vega.VegaLite: TSubtitleFontWeight :: FontWeight -> TitleConfig
+ Graphics.Vega.VegaLite: TSubtitleLineHeight :: Double -> TitleConfig
+ Graphics.Vega.VegaLite: TSubtitlePadding :: Double -> TitleConfig
+ Graphics.Vega.VegaLite: TdX :: Double -> TitleConfig
+ Graphics.Vega.VegaLite: TdY :: Double -> TitleConfig
+ Graphics.Vega.VegaLite: TickBand :: BandAlign -> AxisConfig
+ Graphics.Vega.VegaLite: TitleLineHeight :: Double -> AxisConfig
+ Graphics.Vega.VegaLite: TranslateOffset :: Double -> AxisConfig
+ Graphics.Vega.VegaLite: ViewBackgroundStyle :: [ViewBackground] -> ViewConfig
+ Graphics.Vega.VegaLite: ViewContinuousHeight :: Double -> ViewConfig
+ Graphics.Vega.VegaLite: ViewContinuousWidth :: Double -> ViewConfig
+ Graphics.Vega.VegaLite: ViewDiscreteHeight :: Double -> ViewConfig
+ Graphics.Vega.VegaLite: ViewDiscreteWidth :: Double -> ViewConfig
+ Graphics.Vega.VegaLite: ViewStep :: Double -> ViewConfig
+ Graphics.Vega.VegaLite: data BandAlign
+ Graphics.Vega.VegaLite: data BindLegendProperty
+ Graphics.Vega.VegaLite: data ColorGradient
+ Graphics.Vega.VegaLite: data ConditionalAxisProperty
+ Graphics.Vega.VegaLite: data ConfigureSpec
+ Graphics.Vega.VegaLite: data DensityProperty
+ Graphics.Vega.VegaLite: data EncodingSpec
+ Graphics.Vega.VegaLite: data GradientProperty
+ Graphics.Vega.VegaLite: data LoessProperty
+ Graphics.Vega.VegaLite: data LookupFields
+ Graphics.Vega.VegaLite: data PivotProperty
+ Graphics.Vega.VegaLite: data QuantileProperty
+ Graphics.Vega.VegaLite: data RegressionMethod
+ Graphics.Vega.VegaLite: data RegressionProperty
+ Graphics.Vega.VegaLite: data ResolveSpec
+ Graphics.Vega.VegaLite: data SelectSpec
+ Graphics.Vega.VegaLite: data TextDirection
+ Graphics.Vega.VegaLite: data TransformSpec
+ Graphics.Vega.VegaLite: density :: FieldName -> [DensityProperty] -> BuildTransformSpecs
+ Graphics.Vega.VegaLite: fromConfigureSpec :: ConfigureSpec -> (Text, VLSpec)
+ Graphics.Vega.VegaLite: fromEncodingSpec :: EncodingSpec -> (Text, VLSpec)
+ Graphics.Vega.VegaLite: fromResolveSpec :: ResolveSpec -> (Text, VLSpec)
+ Graphics.Vega.VegaLite: fromSelectSpec :: SelectSpec -> (SelectionLabel, VLSpec)
+ Graphics.Vega.VegaLite: fromTransformSpec :: TransformSpec -> VLSpec
+ Graphics.Vega.VegaLite: heightOfContainer :: PropertySpec
+ Graphics.Vega.VegaLite: heightStep :: Double -> PropertySpec
+ Graphics.Vega.VegaLite: loess :: FieldName -> FieldName -> [LoessProperty] -> BuildTransformSpecs
+ Graphics.Vega.VegaLite: lookupSelection :: FieldName -> SelectionLabel -> FieldName -> BuildTransformSpecs
+ Graphics.Vega.VegaLite: pivot :: FieldName -> FieldName -> [PivotProperty] -> BuildTransformSpecs
+ Graphics.Vega.VegaLite: quantile :: FieldName -> [QuantileProperty] -> BuildTransformSpecs
+ Graphics.Vega.VegaLite: regression :: FieldName -> FieldName -> [RegressionProperty] -> BuildTransformSpecs
+ Graphics.Vega.VegaLite: toConfigureSpec :: Text -> VLSpec -> ConfigureSpec
+ Graphics.Vega.VegaLite: toEncodingSpec :: Text -> VLSpec -> EncodingSpec
+ Graphics.Vega.VegaLite: toResolveSpec :: Text -> VLSpec -> ResolveSpec
+ Graphics.Vega.VegaLite: toSelectSpec :: SelectionLabel -> VLSpec -> SelectSpec
+ Graphics.Vega.VegaLite: toTransformSpec :: VLSpec -> TransformSpec
+ Graphics.Vega.VegaLite: type BuildConfigureSpecs = [ConfigureSpec] -> [ConfigureSpec]
+ Graphics.Vega.VegaLite: type BuildEncodingSpecs = [EncodingSpec] -> [EncodingSpec]
+ Graphics.Vega.VegaLite: type BuildResolveSpecs = [ResolveSpec] -> [ResolveSpec]
+ Graphics.Vega.VegaLite: type BuildSelectSpecs = [SelectSpec] -> [SelectSpec]
+ Graphics.Vega.VegaLite: type BuildTransformSpecs = [TransformSpec] -> [TransformSpec]
+ Graphics.Vega.VegaLite: type DashOffset = Double
+ Graphics.Vega.VegaLite: type DashStyle = [Double]
+ Graphics.Vega.VegaLite: type FieldName = Text
+ Graphics.Vega.VegaLite: type GradientCoord = Double
+ Graphics.Vega.VegaLite: type GradientStops = [(GradientCoord, Color)]
+ Graphics.Vega.VegaLite: type SelectionLabel = Text
+ Graphics.Vega.VegaLite: type VegaExpr = Text
+ Graphics.Vega.VegaLite: url :: [HyperlinkChannel] -> BuildEncodingSpecs
+ Graphics.Vega.VegaLite: widthOfContainer :: PropertySpec
+ Graphics.Vega.VegaLite: widthStep :: Double -> PropertySpec
- Graphics.Vega.VegaLite: ArgMax :: Maybe Text -> Operation
+ Graphics.Vega.VegaLite: ArgMax :: Maybe FieldName -> Operation
- Graphics.Vega.VegaLite: ArgMin :: Maybe Text -> Operation
+ Graphics.Vega.VegaLite: ArgMin :: Maybe FieldName -> Operation
- Graphics.Vega.VegaLite: AxDomainDash :: [Double] -> AxisProperty
+ Graphics.Vega.VegaLite: AxDomainDash :: DashStyle -> AxisProperty
- Graphics.Vega.VegaLite: AxDomainDashOffset :: Double -> AxisProperty
+ Graphics.Vega.VegaLite: AxDomainDashOffset :: DashOffset -> AxisProperty
- Graphics.Vega.VegaLite: AxGridDash :: [Double] -> AxisProperty
+ Graphics.Vega.VegaLite: AxGridDash :: DashStyle -> AxisProperty
- Graphics.Vega.VegaLite: AxGridDashOffset :: Double -> AxisProperty
+ Graphics.Vega.VegaLite: AxGridDashOffset :: DashOffset -> AxisProperty
- Graphics.Vega.VegaLite: AxTickDash :: [Double] -> AxisProperty
+ Graphics.Vega.VegaLite: AxTickDash :: DashStyle -> AxisProperty
- Graphics.Vega.VegaLite: AxTickDashOffset :: Double -> AxisProperty
+ Graphics.Vega.VegaLite: AxTickDashOffset :: DashOffset -> AxisProperty
- Graphics.Vega.VegaLite: Background :: Text -> ConfigurationProperty
+ Graphics.Vega.VegaLite: Background :: Color -> ConfigurationProperty
- Graphics.Vega.VegaLite: ByFieldOp :: Text -> Operation -> SortProperty
+ Graphics.Vega.VegaLite: ByFieldOp :: FieldName -> Operation -> SortProperty
- Graphics.Vega.VegaLite: ColumnFields :: [Text] -> RepeatFields
+ Graphics.Vega.VegaLite: ColumnFields :: [FieldName] -> RepeatFields
- Graphics.Vega.VegaLite: DName :: Text -> DetailChannel
+ Graphics.Vega.VegaLite: DName :: FieldName -> DetailChannel
- Graphics.Vega.VegaLite: DomainDash :: [Double] -> AxisConfig
+ Graphics.Vega.VegaLite: DomainDash :: DashStyle -> AxisConfig
- Graphics.Vega.VegaLite: DomainDashOffset :: Double -> AxisConfig
+ Graphics.Vega.VegaLite: DomainDashOffset :: DashOffset -> AxisConfig
- Graphics.Vega.VegaLite: Expr :: Text -> BooleanOp
+ Graphics.Vega.VegaLite: Expr :: VegaExpr -> BooleanOp
- Graphics.Vega.VegaLite: FEqual :: Text -> DataValue -> Filter
+ Graphics.Vega.VegaLite: FEqual :: FieldName -> DataValue -> Filter
- Graphics.Vega.VegaLite: FExpr :: Text -> Filter
+ Graphics.Vega.VegaLite: FExpr :: VegaExpr -> Filter
- Graphics.Vega.VegaLite: FGreaterThan :: Text -> DataValue -> Filter
+ Graphics.Vega.VegaLite: FGreaterThan :: FieldName -> DataValue -> Filter
- Graphics.Vega.VegaLite: FGreaterThanEq :: Text -> DataValue -> Filter
+ Graphics.Vega.VegaLite: FGreaterThanEq :: FieldName -> DataValue -> Filter
- Graphics.Vega.VegaLite: FLessThan :: Text -> DataValue -> Filter
+ Graphics.Vega.VegaLite: FLessThan :: FieldName -> DataValue -> Filter
- Graphics.Vega.VegaLite: FLessThanEq :: Text -> DataValue -> Filter
+ Graphics.Vega.VegaLite: FLessThanEq :: FieldName -> DataValue -> Filter
- Graphics.Vega.VegaLite: FName :: Text -> FacetChannel
+ Graphics.Vega.VegaLite: FName :: FieldName -> FacetChannel
- Graphics.Vega.VegaLite: FOneOf :: Text -> DataValues -> Filter
+ Graphics.Vega.VegaLite: FOneOf :: FieldName -> DataValues -> Filter
- Graphics.Vega.VegaLite: FRange :: Text -> FilterRange -> Filter
+ Graphics.Vega.VegaLite: FRange :: FieldName -> FilterRange -> Filter
- Graphics.Vega.VegaLite: FSelection :: Text -> Filter
+ Graphics.Vega.VegaLite: FSelection :: SelectionLabel -> Filter
- Graphics.Vega.VegaLite: FValid :: Text -> Filter
+ Graphics.Vega.VegaLite: FValid :: FieldName -> Filter
- Graphics.Vega.VegaLite: Fields :: [Text] -> SelectionProperty
+ Graphics.Vega.VegaLite: Fields :: [FieldName] -> SelectionProperty
- Graphics.Vega.VegaLite: GridDash :: [Double] -> AxisConfig
+ Graphics.Vega.VegaLite: GridDash :: DashStyle -> AxisConfig
- Graphics.Vega.VegaLite: GridDashOffset :: Double -> AxisConfig
+ Graphics.Vega.VegaLite: GridDashOffset :: DashOffset -> AxisConfig
- Graphics.Vega.VegaLite: HName :: Text -> HyperlinkChannel
+ Graphics.Vega.VegaLite: HName :: FieldName -> HyperlinkChannel
- Graphics.Vega.VegaLite: ImGroupBy :: [Text] -> ImputeProperty
+ Graphics.Vega.VegaLite: ImGroupBy :: [FieldName] -> ImputeProperty
- Graphics.Vega.VegaLite: LSymbolDash :: [Double] -> LegendProperty
+ Graphics.Vega.VegaLite: LSymbolDash :: DashStyle -> LegendProperty
- Graphics.Vega.VegaLite: LSymbolDashOffset :: Double -> LegendProperty
+ Graphics.Vega.VegaLite: LSymbolDashOffset :: DashOffset -> LegendProperty
- Graphics.Vega.VegaLite: LeStrokeDash :: [Double] -> LegendConfig
+ Graphics.Vega.VegaLite: LeStrokeDash :: DashStyle -> LegendConfig
- Graphics.Vega.VegaLite: LeSymbolDash :: [Double] -> LegendConfig
+ Graphics.Vega.VegaLite: LeSymbolDash :: DashStyle -> LegendConfig
- Graphics.Vega.VegaLite: LeSymbolDashOffset :: Double -> LegendConfig
+ Graphics.Vega.VegaLite: LeSymbolDashOffset :: DashOffset -> LegendConfig
- Graphics.Vega.VegaLite: MFill :: Text -> MarkProperty
+ Graphics.Vega.VegaLite: MFill :: Color -> MarkProperty
- Graphics.Vega.VegaLite: MName :: Text -> MarkChannel
+ Graphics.Vega.VegaLite: MName :: FieldName -> MarkChannel
- Graphics.Vega.VegaLite: MStroke :: Text -> MarkProperty
+ Graphics.Vega.VegaLite: MStroke :: Color -> MarkProperty
- Graphics.Vega.VegaLite: MStrokeDash :: [Double] -> MarkProperty
+ Graphics.Vega.VegaLite: MStrokeDash :: DashStyle -> MarkProperty
- Graphics.Vega.VegaLite: MStrokeDashOffset :: Double -> MarkProperty
+ Graphics.Vega.VegaLite: MStrokeDashOffset :: DashOffset -> MarkProperty
- Graphics.Vega.VegaLite: OName :: Text -> OrderChannel
+ Graphics.Vega.VegaLite: OName :: FieldName -> OrderChannel
- Graphics.Vega.VegaLite: PName :: Text -> PositionChannel
+ Graphics.Vega.VegaLite: PName :: FieldName -> PositionChannel
- Graphics.Vega.VegaLite: Parse :: [(Text, DataType)] -> Format
+ Graphics.Vega.VegaLite: Parse :: [(FieldName, DataType)] -> Format
- Graphics.Vega.VegaLite: RowFields :: [Text] -> RepeatFields
+ Graphics.Vega.VegaLite: RowFields :: [FieldName] -> RepeatFields
- Graphics.Vega.VegaLite: SInit :: [(Text, DataValue)] -> SelectionProperty
+ Graphics.Vega.VegaLite: SInit :: [(FieldName, DataValue)] -> SelectionProperty
- Graphics.Vega.VegaLite: SMFill :: Text -> SelectionMarkProperty
+ Graphics.Vega.VegaLite: SMFill :: Color -> SelectionMarkProperty
- Graphics.Vega.VegaLite: SMStroke :: Text -> SelectionMarkProperty
+ Graphics.Vega.VegaLite: SMStroke :: Color -> SelectionMarkProperty
- Graphics.Vega.VegaLite: SMStrokeDash :: [Double] -> SelectionMarkProperty
+ Graphics.Vega.VegaLite: SMStrokeDash :: DashStyle -> SelectionMarkProperty
- Graphics.Vega.VegaLite: SMStrokeDashOffset :: Double -> SelectionMarkProperty
+ Graphics.Vega.VegaLite: SMStrokeDashOffset :: DashOffset -> SelectionMarkProperty
- Graphics.Vega.VegaLite: Selection :: Text -> BooleanOp
+ Graphics.Vega.VegaLite: Selection :: SelectionLabel -> BooleanOp
- Graphics.Vega.VegaLite: SelectionName :: Text -> BooleanOp
+ Graphics.Vega.VegaLite: SelectionName :: SelectionLabel -> BooleanOp
- Graphics.Vega.VegaLite: TName :: Text -> TextChannel
+ Graphics.Vega.VegaLite: TName :: FieldName -> TextChannel
- Graphics.Vega.VegaLite: TickDash :: [Double] -> AxisConfig
+ Graphics.Vega.VegaLite: TickDash :: DashStyle -> AxisConfig
- Graphics.Vega.VegaLite: TickDashOffset :: Double -> AxisConfig
+ Graphics.Vega.VegaLite: TickDashOffset :: DashOffset -> AxisConfig
- Graphics.Vega.VegaLite: VBFill :: Maybe Text -> ViewBackground
+ Graphics.Vega.VegaLite: VBFill :: Maybe Color -> ViewBackground
- Graphics.Vega.VegaLite: VBStroke :: Maybe Text -> ViewBackground
+ Graphics.Vega.VegaLite: VBStroke :: Maybe Color -> ViewBackground
- Graphics.Vega.VegaLite: VBStrokeDash :: [Double] -> ViewBackground
+ Graphics.Vega.VegaLite: VBStrokeDash :: DashStyle -> ViewBackground
- Graphics.Vega.VegaLite: VBStrokeDashOffset :: Double -> ViewBackground
+ Graphics.Vega.VegaLite: VBStrokeDashOffset :: DashOffset -> ViewBackground
- Graphics.Vega.VegaLite: ViewFill :: Maybe Text -> ViewConfig
+ Graphics.Vega.VegaLite: ViewFill :: Maybe Color -> ViewConfig
- Graphics.Vega.VegaLite: ViewStroke :: Maybe Text -> ViewConfig
+ Graphics.Vega.VegaLite: ViewStroke :: Maybe Color -> ViewConfig
- Graphics.Vega.VegaLite: ViewStrokeDash :: [Double] -> ViewConfig
+ Graphics.Vega.VegaLite: ViewStrokeDash :: DashStyle -> ViewConfig
- Graphics.Vega.VegaLite: ViewStrokeDashOffset :: Double -> ViewConfig
+ Graphics.Vega.VegaLite: ViewStrokeDashOffset :: DashOffset -> ViewConfig
- Graphics.Vega.VegaLite: WAscending :: Text -> SortField
+ Graphics.Vega.VegaLite: WAscending :: FieldName -> SortField
- Graphics.Vega.VegaLite: WDescending :: Text -> SortField
+ Graphics.Vega.VegaLite: WDescending :: FieldName -> SortField
- Graphics.Vega.VegaLite: WField :: Text -> Window
+ Graphics.Vega.VegaLite: WField :: FieldName -> Window
- Graphics.Vega.VegaLite: WGroupBy :: [Text] -> WindowProperty
+ Graphics.Vega.VegaLite: WGroupBy :: [FieldName] -> WindowProperty
- Graphics.Vega.VegaLite: aggregate :: [VLSpec] -> [Text] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: aggregate :: [VLSpec] -> [FieldName] -> BuildTransformSpecs
- Graphics.Vega.VegaLite: background :: Text -> PropertySpec
+ Graphics.Vega.VegaLite: background :: Color -> PropertySpec
- Graphics.Vega.VegaLite: binAs :: [BinProperty] -> Text -> Text -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: binAs :: [BinProperty] -> FieldName -> FieldName -> BuildTransformSpecs
- Graphics.Vega.VegaLite: calculateAs :: Text -> Text -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: calculateAs :: VegaExpr -> FieldName -> BuildTransformSpecs
- Graphics.Vega.VegaLite: categoricalDomainMap :: [(Text, Text)] -> [ScaleProperty]
+ Graphics.Vega.VegaLite: categoricalDomainMap :: [(Text, Color)] -> [ScaleProperty]
- Graphics.Vega.VegaLite: color :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: color :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: column :: [FacetChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: column :: [FacetChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: configuration :: ConfigurationProperty -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: configuration :: ConfigurationProperty -> BuildConfigureSpecs
- Graphics.Vega.VegaLite: configure :: [LabelledSpec] -> PropertySpec
+ Graphics.Vega.VegaLite: configure :: [ConfigureSpec] -> PropertySpec
- Graphics.Vega.VegaLite: dataColumn :: Text -> DataValues -> [DataColumn] -> [DataColumn]
+ Graphics.Vega.VegaLite: dataColumn :: FieldName -> DataValues -> [DataColumn] -> [DataColumn]
- Graphics.Vega.VegaLite: dataRow :: [(Text, DataValue)] -> [DataRow] -> [DataRow]
+ Graphics.Vega.VegaLite: dataRow :: [(FieldName, DataValue)] -> [DataRow] -> [DataRow]
- Graphics.Vega.VegaLite: dataSequenceAs :: Double -> Double -> Double -> Text -> Data
+ Graphics.Vega.VegaLite: dataSequenceAs :: Double -> Double -> Double -> FieldName -> Data
- Graphics.Vega.VegaLite: detail :: [DetailChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: detail :: [DetailChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: domainRangeMap :: (Double, Text) -> (Double, Text) -> [ScaleProperty]
+ Graphics.Vega.VegaLite: domainRangeMap :: (Double, Color) -> (Double, Color) -> [ScaleProperty]
- Graphics.Vega.VegaLite: encoding :: [LabelledSpec] -> PropertySpec
+ Graphics.Vega.VegaLite: encoding :: [EncodingSpec] -> PropertySpec
- Graphics.Vega.VegaLite: fill :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: fill :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: fillOpacity :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: fillOpacity :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: filter :: Filter -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: filter :: Filter -> BuildTransformSpecs
- Graphics.Vega.VegaLite: flatten :: [Text] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: flatten :: [FieldName] -> BuildTransformSpecs
- Graphics.Vega.VegaLite: flattenAs :: [Text] -> [Text] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: flattenAs :: [FieldName] -> [FieldName] -> BuildTransformSpecs
- Graphics.Vega.VegaLite: fold :: [Text] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: fold :: [FieldName] -> BuildTransformSpecs
- Graphics.Vega.VegaLite: foldAs :: [Text] -> Text -> Text -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: foldAs :: [FieldName] -> FieldName -> FieldName -> BuildTransformSpecs
- Graphics.Vega.VegaLite: fromVL :: VegaLite -> VLSpec
+ Graphics.Vega.VegaLite: fromVL :: VegaLite -> Value
- Graphics.Vega.VegaLite: hyperlink :: [HyperlinkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: hyperlink :: [HyperlinkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: impute :: Text -> Text -> [ImputeProperty] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: impute :: FieldName -> FieldName -> [ImputeProperty] -> BuildTransformSpecs
- Graphics.Vega.VegaLite: joinAggregate :: [VLSpec] -> [WindowProperty] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: joinAggregate :: [VLSpec] -> [WindowProperty] -> BuildTransformSpecs
- Graphics.Vega.VegaLite: lookup :: Text -> Data -> Text -> [Text] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: lookup :: FieldName -> Data -> FieldName -> LookupFields -> BuildTransformSpecs
- Graphics.Vega.VegaLite: lookupAs :: Text -> Data -> Text -> Text -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: lookupAs :: FieldName -> Data -> FieldName -> FieldName -> BuildTransformSpecs
- Graphics.Vega.VegaLite: opAs :: Operation -> Text -> Text -> VLSpec
+ Graphics.Vega.VegaLite: opAs :: Operation -> FieldName -> FieldName -> VLSpec
- Graphics.Vega.VegaLite: opacity :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: opacity :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: order :: [OrderChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: order :: [OrderChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: position :: Position -> [PositionChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: position :: Position -> [PositionChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: repeatFlow :: [Text] -> PropertySpec
+ Graphics.Vega.VegaLite: repeatFlow :: [FieldName] -> PropertySpec
- Graphics.Vega.VegaLite: resolution :: Resolve -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: resolution :: Resolve -> BuildResolveSpecs
- Graphics.Vega.VegaLite: resolve :: [LabelledSpec] -> PropertySpec
+ Graphics.Vega.VegaLite: resolve :: [ResolveSpec] -> PropertySpec
- Graphics.Vega.VegaLite: row :: [FacetChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: row :: [FacetChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: sample :: Int -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: sample :: Int -> BuildTransformSpecs
- Graphics.Vega.VegaLite: select :: Text -> Selection -> [SelectionProperty] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: select :: SelectionLabel -> Selection -> [SelectionProperty] -> BuildSelectSpecs
- Graphics.Vega.VegaLite: selection :: [LabelledSpec] -> PropertySpec
+ Graphics.Vega.VegaLite: selection :: [SelectSpec] -> PropertySpec
- Graphics.Vega.VegaLite: shape :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: shape :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: size :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: size :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: stack :: Text -> [Text] -> Text -> Text -> [StackProperty] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: stack :: FieldName -> [FieldName] -> FieldName -> FieldName -> [StackProperty] -> BuildTransformSpecs
- Graphics.Vega.VegaLite: stroke :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: stroke :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: strokeOpacity :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: strokeOpacity :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: strokeWidth :: [MarkChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: strokeWidth :: [MarkChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: text :: [TextChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: text :: [TextChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: timeUnitAs :: TimeUnit -> Text -> Text -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: timeUnitAs :: TimeUnit -> FieldName -> FieldName -> BuildTransformSpecs
- Graphics.Vega.VegaLite: tooltip :: [TextChannel] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: tooltip :: [TextChannel] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: tooltips :: [[TextChannel]] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: tooltips :: [[TextChannel]] -> BuildEncodingSpecs
- Graphics.Vega.VegaLite: transform :: [LabelledSpec] -> PropertySpec
+ Graphics.Vega.VegaLite: transform :: [TransformSpec] -> PropertySpec
- Graphics.Vega.VegaLite: window :: [([Window], Text)] -> [WindowProperty] -> BuildLabelledSpecs
+ Graphics.Vega.VegaLite: window :: [([Window], FieldName)] -> [WindowProperty] -> BuildTransformSpecs

This diff is very large; some files are shown as “too large to diff”. Download the raw patch for the complete diff.

Files

CHANGELOG.md view
@@ -1,6 +1,177 @@ 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.5.0.0++Update to version 4.0 of the Vega-Lite specification (tested against+version 4.0.2). There are several changes in default behavior due+to this (tooltips are now disabled by default, the background now defaults+to white rather than transparent), although this is also controlled by+how the Vega-Lite visualization is rendered, which can make tracking+down why something has changed a bit awkward.++There is more-extensive use of type aliases, such as `Color`,+and the introduction of several more (e.g. `DashStyle` and `FieldName`).+These do not add any type safety, but help the documentation (as they provide+a single place to explain the meaning and any constraints on a+particular value). There are some changes that do improve type safety,+discussed in the "Breaking changes" section below.++Documentation improvements, including a new section in the+tutorial on choropleths contributed by Adam Conner-Sax, and+plots using an Aitoff projection contributed by Jo Wood.++### New functionality++Title (and subtitle) strings can now be split across multiple lines:+use '\n' to indicate a line break.++Colors are now stripped of extraneous white space, and if empty+converted to the JSON null value rather than an empty string.++The `pivot` transform has been added, along with the `PivotProperty`+preferences type. This is the inverse of `fold`.++The `density` transform has been added, along with the `DensityProperty`+configuration type, to support kernel density estimation (e.g. to+generate a continuous distribtion from a discrete one).++The `loess` transform has been added, along with the `LoessProperty`+configuration type, to support scatterplot smoothing.++The `regression` transform has been added, along with the `RegressionProperty`+and `RegressionMethod` configuration types, to support regression+analysis.++The `quantile` transform has been added, along with the `QuantileProperty`+type, to support quantile analysis.++The `url` encoding has been added, which allows you to view images (e.g.+PNG) via the (new) `Image` mark type. The `MAspect` `MarkProperty` has+been added as a configuration option.++The `lookupSelection` transform has been added to support joining+data via a selection. The `SelectionLabel` type alias has been added+to help the documentation.++The `heightOfContainer` and `widthOfContainer` functions+have been added to support responsive sizing, although I have not had+much success in getting them to work!++The `tooltip` encoding will now turn off tooltips if given an empty+list (although note that tooltips are now off by default in Vega-Lite 4).++### Breaking changes++The `combineSpecs` function has been removed.++In an attempt to provide some type safety, the `encoding`,+`transform`, `resolve`, `selection`, and `configure` functions now+take specialised types (`EncodingSpec`, `TransformSpec`,+`ResolveSpec`, `SelectSpec`, and `ConfigureSpec` respectively) rather+than the generic `LabelledSpec` type. Simple visualizations should+remain unchanged, but helper functions may need to have their type+signatures updated.++The `lookup` transform has been changed so that the list of fields+stored when the keys match is now specified by the `LookupFields`+type (rather than a list of field names). This supports providing+aliases and handling of default values, and now subsumes the `lookupAs`+encoding, which has been marked as deprecated.++The `RemoveInvalid` constructor has removed from `ConfigurationProperty`,+and has been replaced by the `MRemoveInvalid` constructor of+`MarkProperty`. The `Stack` constructor was removed.++The `SRangeStep` constructor from `ScaleProperty` has been removed.+The `widthStep` and `heightStep` functions should be used instead.++The `ViewWidth` and `ViewHeight` constuctors of `ViewConfig` have+been replaced by `ViewContinuousWidth`, `ViewContinuousHeight`,+`ViewDiscreteWidth`, and `ViewDiscreteHeight` (well, the symbols+remain but have been deprecated for the continous-named versions).++The `SCRangeStep` and `SCTextXRangeStep` constructors of `ScaleConfig`+have been removed. The new `ViewStep` constructor of `ViewConfig` should be+used as a replacement.++The `ShortTimeLabels`, `LeShortTimeLabels`, and `MShortTimeLabels`+constructors - from `AxisConfig`, `LegendConfg`, and `MarkProperty`+respectively - have been removed.++### New constructors++This section does not repeat names mentioned above.++`AxisProperty` has gained the `AxDataCondition` constructor for+marking a subset of axis properties as being conditional on their+position, and the `ConditionalAxisProperty` for defining which+properties (grid, label, and tick) can be used in this way. It has+also gained the `AxLabelExpr` constructor, which allows you to+change the content of axis labels, `AxTickBand` for positioning the+labels for band scales (and the associated `BandAlign` type),+`AxTitleLineHeight` to specify the line height, and `AxTranslateOffset`+for applying a translation offset to the axis group.++`AxisConfig` has gained `TickBand`, `TitleLineHeight`, and+`TranslateOffset`, matching the additions to `AxisProperty`.++The `ViewBackgroundStyle` constructor has been added to `ViewConfig`.++The `TitleConfig` type gained the following constructors:+`TAlign`, `TdX`, `TdY`, `TLineHeight`, `TSubtitle`, `TSubtitleColor`,+`TSubtitleFont`, `TSubtitleFontSize`, `TSubtitleFontStyle`,+`TSubtitleFontWeight`, `TSubtitleLineHeight`, and `TSubtitlePadding`.++Added `AFitX` and `AFitY` constructors to the `Autosize` type.++The `SelectionProperty` type has gained the `BindLegend` constructor,+and the associated `BindLegendProperty` type, to allow selection of+a legend (categorical data only).++The `TextChannel` type has gained the `TString` constructor, which+lets you specify the text content as a literal.++Two new projections - `EqualEarth` and `NaturalEarth1` - have been+added to the `Projection` type.++Support for color gradients has been added for marks via the+`MColorGradient`, `MFillGradient`, and `MStrokeGradient` constructors of+`MarkProperty`, along with the new `ColorGradient` and+`GradientProperty` types for defining the appearance of the+gradient. The `GradientCoord` and `GradientStops` type aliases+have also been added (although they provides no type safety).++The `MCornerRadius`, `MCornerRadiusTL`, `MCornerRadiusTR`, `MCornerRadiusBL`,+and `MCornerRadiusBR` constructors have been added to `MarkProperty` to+set the corner radii of rectangular marks.++The `MDir`, `MEllipsis`, and `MLimit` constructors have been added to+`MarkProperty` to control how text is truncated. The `TextDirection` type+has been added for use with `MDir`.++The `MarkProperty` type has gained `MLineBreak` and `MLineHeight` constructors+for controlling how multi-line labels are displayed. Note that `hvega` will+always split on the newline character (`\n`), which will over-ride the+`MLineBreak` setting.++The `DTMonthNum` and `DTDayNum` constructors have been added to `DateTime`.++The `BinProperty` type has gained the `SelectionExtent`+constructor, for defining a bin range via an interval selection.++The `PositionChannel` type has gained the `PBand` constructor,+for defining the size of a mark relative to a band, and `MarkProperty`+has added `MTimeUnitBand` and `MTimeUnitBandPosition`.++### Bug fixes++The selection property `SInitInterval Nothing Nothing` is now a+no-op (as it does nothing), rather than generating invalid JSON.++The following options or symbols generated incorrect JSON output:+`ONone`, `LSymbolStrokeWidth`, `LeLabelOpacity`.+ ## 0.4.1.2  Documentation fix (rendering of a URL), provided by Alexey Kuleshevich@@ -143,7 +314,7 @@ The LineMarker and PointMarker types have been added for use with `MLine` and `MPoint` respectively (both from `MarkProperty`). -The ability to define the binning property with +The ability to define the binning property with `binAs`, `DBin`, `FBin`, `HBin`, `MBin`, `OBin`, `PBin`, and `TBin` has been expanded by adding the `AlreadyBinned` and `BinAnchor` constructors to `BinProperty`, as well as changing the `Divide`
README.md view
@@ -1,7 +1,7 @@ # hvega  Create [Vega-Lite](https://vega.github.io/vega-lite/) visualizations in-Haskell. It targets version 3 of the Vega-Lite specification. Note that+Haskell. It targets version 4 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),@@ -80,4 +80,6 @@ is a separate type from the input values - that is `VegaLite` and `VLSpec` - since it makes it easier to display the output of `hvega` in `IHaskell`. The JSON specification is retrieved from-this type with `fromVL`.+this type with `fromVL`. The `0.5.0.0` release adds some more+type safety (restricting the functions that can be applied+to `encoding` and `transform` for instance).
default.nix view
@@ -1,2 +1,2 @@-{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc865" }:+{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc882" }: nixpkgs.pkgs.haskell.packages.${compiler}.callPackage ./hvega.nix { }
hvega.cabal view
@@ -1,6 +1,6 @@ name:                hvega-version:             0.4.1.2-synopsis:            Create Vega-Lite visualizations (version 3) in Haskell.+version:             0.5.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>)                      by Jo Wood of the giCentre at the City University of London.@@ -10,7 +10,7 @@ license-file:        LICENSE author:              Douglas Burke maintainer:          dburke.gw@gmail.com-copyright:           2018-2019 Douglas Burke+copyright:           2018-2020 Douglas Burke category:            Graphics build-type:          Simple extra-source-files:  README.md@@ -28,6 +28,7 @@                      tests/specs/fillstroke/*.vl                      tests/specs/geo/*.vl                      tests/specs/hyperlink/*.vl+                     tests/specs/image/*.vl                      tests/specs/interaction/*.vl                      tests/specs/legend/*.vl                      tests/specs/null/*.vl@@ -73,18 +74,28 @@                      images/vl/gmaghistogramwithcolor.png                      images/vl/gmaglinewithcolor.png                      images/vl/yhistogram.png+                     images/vl/starcount.png+                     images/vl/starcount2.png+                     images/vl/densityparallax.png+                     images/vl/densityparallaxgrouped.png                      images/vl/pointplot.png                      images/vl/posplot.png                      images/vl/skyplot.png                      images/vl/smallmultiples.png                      images/vl/smallmultiples2.png+                     images/vl/densitymultiples.png                      images/vl/baseplot.png                      images/vl/layeredplot.png                      images/vl/layereddiversion.png+                     images/vl/layeredcount.png+                     images/vl/skyplotwithgraticules.png                      images/vl/concatenatedplot.png                      images/vl/concatenatedplot2.png+                     images/vl/concatenatedskyplot.png                      images/vl/repeatplot.png                      images/vl/splomplot.png+                     images/vl/choroplethlookuptogeo.png+                     images/vl/choroplethlookupfromgeo.png                      images/vl/singleselection.png                      images/vl/nearestselection.png                      images/vl/multiselection.png@@ -92,12 +103,15 @@                      images/vl/intervalselection.png                      images/vl/intervalselectiony.png                      images/vl/transformselection.png+                     images/vl/legendselection.png                      images/vl/widgetselection.png                      images/vl/bindscales.png                      images/vl/coordinatedviews.png                      images/vl/coordinatedviews2.png                      images/vl/contextandfocus.png                      images/vl/crossfilter.png+                     images/vl/loessexample.png+                     images/vl/regressionexample.png                      images/vl/errormanual.png                      images/vl/errormanual-zoomed.png                      images/vl/errorauto.png@@ -107,6 +121,12 @@                      images/vl/comparingerrors.png                      images/vl/combinedplot.png                      images/vl/combinedplot-selected.png+                     images/vl/duplicateaxis.png+                     images/vl/comparecounts.png+                     images/vl/parallaxview.png+                     images/vl/parallaxview-selected.png+                     images/vl/skyplotaitoff.png+                     images/vl/clustercenters.png  cabal-version:       1.18 @@ -122,12 +142,25 @@   hs-source-dirs:      src   exposed-modules:     Graphics.Vega.VegaLite                        Graphics.Vega.Tutorials.VegaLite+  other-modules:       Graphics.Vega.VegaLite.Configuration+                       Graphics.Vega.VegaLite.Core+                       Graphics.Vega.VegaLite.Data+                       Graphics.Vega.VegaLite.Foundation+                       Graphics.Vega.VegaLite.Geometry+                       Graphics.Vega.VegaLite.Input+                       Graphics.Vega.VegaLite.Legend+                       Graphics.Vega.VegaLite.Mark+                       Graphics.Vega.VegaLite.Output+                       Graphics.Vega.VegaLite.Scale+                       Graphics.Vega.VegaLite.Selection+                       Graphics.Vega.VegaLite.Specification+                       Graphics.Vega.VegaLite.Time+                       Graphics.Vega.VegaLite.Transform   build-depends:       base >= 4.9 && < 5                      , aeson >= 0.11 && < 1.5                      , text == 1.2.*                      , unordered-containers == 0.2.*-                     , vector >= 0.11 && < 0.13-                     +   default-language:    Haskell2010   ghc-options:         -Wall @@ -144,6 +177,7 @@                        FillStrokeTests                        GeoTests                        HyperlinkTests+                       ImageTests                        InteractionTests                        LegendTests                        NullTests
hvega.nix view
@@ -1,21 +1,18 @@ { mkDerivation, aeson, aeson-pretty, base, bytestring, containers , filepath, stdenv, tasty, tasty-golden, text, unordered-containers-, vector }: mkDerivation {   pname = "hvega";-  version = "0.4.1.2";+  version = "0.5.0.0";   src = ./.;   isLibrary = true;   isExecutable = true;-  libraryHaskellDepends = [-    aeson base text unordered-containers vector-  ];+  libraryHaskellDepends = [ aeson base text unordered-containers ];   testHaskellDepends = [     aeson aeson-pretty base bytestring containers filepath tasty     tasty-golden text   ];   homepage = "https://github.com/DougBurke/hvega";-  description = "Create Vega-Lite visualizations (version 3) in Haskell";+  description = "Create Vega-Lite visualizations (version 4) in Haskell";   license = stdenv.lib.licenses.bsd3; }
+ images/vl/choroplethlookupfromgeo.png view

binary file changed (absent → 87323 bytes)

+ images/vl/choroplethlookuptogeo.png view

binary file changed (absent → 115633 bytes)

+ images/vl/clustercenters.png view

binary file changed (absent → 59849 bytes)

+ images/vl/comparecounts.png view

binary file changed (absent → 14167 bytes)

images/vl/comparingerrors.png view

binary file changed (27031 → 35155 bytes)

+ images/vl/concatenatedskyplot.png view

binary file changed (absent → 110773 bytes)

+ images/vl/densitymultiples.png view

binary file changed (absent → 43543 bytes)

+ images/vl/densityparallax.png view

binary file changed (absent → 10441 bytes)

+ images/vl/densityparallaxgrouped.png view

binary file changed (absent → 16573 bytes)

+ images/vl/duplicateaxis.png view

binary file changed (absent → 7979 bytes)

+ images/vl/layeredcount.png view

binary file changed (absent → 14993 bytes)

+ images/vl/legendselection.png view

binary file changed (absent → 37852 bytes)

+ images/vl/loessexample.png view

binary file changed (absent → 67239 bytes)

+ images/vl/parallaxview-selected.png view

binary file changed (absent → 30921 bytes)

+ images/vl/parallaxview.png view

binary file changed (absent → 32010 bytes)

+ images/vl/regressionexample.png view

binary file changed (absent → 65118 bytes)

images/vl/skyplot.png view

binary file changed (10899 → 16411 bytes)

+ images/vl/skyplotaitoff.png view

binary file changed (absent → 68026 bytes)

+ images/vl/skyplotwithgraticules.png view

binary file changed (absent → 22669 bytes)

+ images/vl/starcount.png view

binary file changed (absent → 11728 bytes)

+ images/vl/starcount2.png view

binary file changed (absent → 11715 bytes)

shell.nix view
@@ -1,2 +1,2 @@-{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc865" }:+{ nixpkgs ? import <nixpkgs> {}, compiler ? "ghc882" }: (import ./default.nix { inherit nixpkgs compiler; }).env
src/Graphics/Vega/Tutorials/VegaLite.hs view
@@ -1,3578 +1,6037 @@-{-# LANGUAGE OverloadedStrings #-}--{-|-Module      : Graphics.Vega.Tutorials.VegaLite-Copyright   : (c) Douglas Burke, 2019-License     : BSD3--Maintainer  : dburke.gw@gmail.com--This tutorial is inspired by - in that it starts off as a close copy of - the-<https://github.com/gicentre/elm-vegalite/tree/master/docs/walkthrough Elm Vega-Lite walkthrough>-created by Jo Wood, and-converted as necessary for the differences between @hvega@ and-<https://package.elm-lang.org/packages/gicentre/elm-vegalite/latest elm-vegalite>.-The Elm tutorial is based on the talk given by-<https://youtu.be/9uaHRWj04D4 Wongsuphasawat et al at the 2017 Open Vis Conf>.--The tutorial targets version 3 of the Vega-Lite specification and-the functionality provided in version @0.4.0.0@ of hvega.---}--module Graphics.Vega.Tutorials.VegaLite (--  -- * A Grammar of Graphics-  ---  -- $intro--  -- ** How many Haskell extensions do you need?-  ---  -- $intro-extensions--  -- ** A note on type safety-  ---  -- $intro-type-safety--  -- ** Comparing hvega to Elm Vega-Lite-  ---  -- $compare-to-elm-  -  -- * What data are we using?-  ---  -- $datasource--  -- * Creating the Vega-Lite visualization-  ---  -- $output-  -  -- * A Strip Plot-  ---  -- $singleview-stripplot--  -- ** Our first hvega plot-  ---  stripPlot--  -- ** Backgrounds-  ---  -- $background-note--  , stripPlotWithBackground-  -  -- ** Challenging the primacy of the x axis-  ---  , stripPlotY--  -- ** Data sources-  ---  -  , gaiaData--  -- ** Adding color as an encoding--  , stripPlotWithColor--  -- ** Comparing Ordinal with Nominal data types-  ---  -- $stripplot-mmtype--  , stripPlotWithColorOrdinal--  -- * Adding an axis-  ---  -- $add-axis--  , parallaxBreakdown--  -- ** Creating a value to plot: aggregating data-  ---  -- $histogram-  -  , simpleHistogram-  , parallaxHistogram-  , gmagHistogram-  -  -- ** Changing the scale of an axis-  ---  -- $ylog-histogram-  -  , ylogHistogram--  -- ** Stacked Histogram--  , gmagHistogramWithColor-  , gmagLineWithColor--  -- ** You don't have to just count-  ---  -- $histogramChoice-  -  , yHistogram--  -- ** Plotting with points-  ---  -- $intro-points--  , pointPlot--  -- * Making a map-  ---  -- $intro-map-  -  , posPlot--  , skyPlot--  -- * Layered and Multi-View Compositions-  ---  -- $intro-layered--  , smallMultiples-  , smallMultiples2--  -- ** One plot, two plot, red plot, blue plot-  ---  -- $intro-multiplot--  , basePlot--  -- ** Composing layers-  -  , layeredPlot-  , layeredDiversion--  -- ** Concatenating views--  , concatenatedPlot-  , concatenatedPlot2--  -- ** Repeated views-  ---  -- $intro-repeat-  -  , repeatPlot-  , splomPlot--  -- * Interactivity-  ---  -- $intro-interactivity--  , selectionProperties-  , singleSelection-  , nearestSelection-  , multiSelection-  , eventSelection-  , intervalSelection-  , intervalSelectionY--  -- ** Selection Transformations-  ---  -- $intro-selection-transforms--  , transformSelection--  -- *** Selection and bindings-  ---  -- $intro-selection-binding--  , widgetSelection-  , bindScales--  -- *** Multiple Coordinated Views-  ---  -- $intro-coordinated-views-  -  , coordinatedViews-  , coordinatedViews2--  , contextAndFocus--  -- *** Cross-filtering-  ---  -- $intro-crossfilter-  -  , crossFilter--  -- * Errors: lines, bars, bands, and boxes-  ---  -- $intro-error-  -  , errorManual-  , errorAuto-  -  , errorBars-  , errorBand-  , errorBox--  , comparingErrors--  -- * Dashboard-esque-  ---  -- $intro-dashboard-  -  , combinedPlot-  -  ) where--import qualified Data.Text as T--import Prelude hiding (filter, lookup, repeat)--import Graphics.Vega.VegaLite---- $intro--- hvega is a wrapper for the [Vega-Lite visualization--- grammar](https://vega.github.io/) which itself is based on Leland--- Wilkinson's [Grammar of--- Graphics](http://www.springer.com/gb/book/9780387245447).  The--- grammar provides an expressive way to define how data are--- represented graphically. The seven key elements of the grammar as--- represented in hvega and Vega-Lite are:------ [@Data@]: The input to visualize. Example functions: 'dataFromUrl', 'dataFromColumns', and 'dataFromRows'.------ [@Transform@]: Functions to change the data before they are visualized. Example functions: 'filter', 'calculateAs', and 'binAs'. These functions are combined with 'transform'.------ [@Projection@]: The mapping of 3d global geospatial locations onto a 2d plane . Example function: 'projection'.------ [@Mark@]: The visual symbol, or symbols, that represent the data. Example types, used with 'mark': 'Line', 'Circle', 'Bar', 'Text', and 'Geoshape'. There are also ways to specify the shape to use for the 'Point' type, using the 'MShape' setting and the 'Symbol' type.------ [@Encoding@]: The specification of which data elements are mapped to which mark characteristics (commonly known as channels). Example functions: 'position', 'shape', 'size', and 'color'. These encodings are combined with 'encoding'.------ [@Scale@]: Descriptions of the way encoded marks represent the data. Example settings: 'SDomain', 'SPadding', and 'SInterpolate'.------ [@Guides@]: Supplementary visual elements that support interpreting the visualization. Example setings: 'AxDomain' (for position encodings) and 'LeTitle' (for legend color, size, and shape encodings).------ In common with other languages that build upon a grammar of graphics--- such as D3 and Vega, this grammar allows fine grain control of--- visualization design. Unlike those languages, Vega-Lite - and--- hvega in turn - provide practical default specifications for most of the--- grammar, allowing for a much more compact high-level form of--- expression.------ The [Vega-Lite Example Gallery](https://vega.github.io/vega-lite/examples/)--- provides a large-number of example visualizations that show off--- the capabilities of Vega-Lite. Hopefully, by the end of this--- tutorial, you will be able to create most of them.---- $intro-extensions--- The 'Graphics.Vega.VegaLite' module is long, but does not use any--- complex type machinery, and so it can be loaded without any extensions,--- although the extensive use of the 'Data.Text.Text' type means that--- using the @OverloadedStrings@ extension is __strongly__ advised.------ The module does export several types that conflict with the Prelude,--- so one suggestion is to use------     > import Prelude hiding (filter, lookup, repeat)---- $intro-type-safety--- The interface provided by @hvega@ provides __limited__ type safety. Various--- fields such as 'PmType' are limited by the type of the argument (in this--- case 'Measurement'), but there's no support to check that the type makes--- sense for the particular column (as @hvega@ itself does not inspect the--- data source). Similarly, @hvega@ does not stop you from defining--- properties that are not valid for a given situation - for instance--- you can say @'toVegaLite' []@ even though the output is not a--- valid Vega-Lite specification (i.e. it does not validate against--- the [Vega-Lite schema](https://github.com/vega/schema)).---- $compare-to-elm--- @hvega@ started out as a direct copy of --- [elm-vegalite](https://package.elm-lang.org/packages/gicentre/elm-vegalite/latest),--- and has been updated to try and match the functionality of that package.--- However, @hvega@ has not (yet?) followed @elm-vegalite@ into using--- functions rather than data structures to define the options: for--- example, @elm-vegalite@ provides @pQuant n@ which in @hvega@ is the--- combination of @'PName' n@ and @'PmType' 'Quantitative'@ in @hvega@.--- The top-level functions - such as 'dataFromUrl', 'encoding', and--- 'filter' - are generally the same.---- $datasource--- Rather than use the Seattle weather dataset, used in the Elm walkthrough--- (if you go through the [Vega-Lite Example Gallery](https://vega.github.io/vega-lite/examples/)--- you may also want to look at different data ;-), I am going to use a--- small datset from the [Gaia satellite](http://sci.esa.int/gaia/),--- which has - and still is, as of Summer 2019 - radically-improved our knowledge--- of our Galaxy. The data itself is from the paper--- \"Gaia Data Release 2: Observational Hertzsprung-Russell diagrams\"--- [preprint on arXiV](https://arxiv.org/abs/1804.09378)--- [NASA ADS link](https://ui.adsabs.harvard.edu/#abs/arXiv:1804.09378).--- We are going to use Table 1a, which was downloaded from the--- [VizieR archive](http://vizier.u-strasbg.fr/viz-bin/VizieR-3?-source=J/A%2bA/616/A10/tablea1a)--- as a tab-separated file (aka 'TSV' format).------ The file contains basic measurements for a number of stars in--- nine open clusters that all lie within 250 parsecs of the Earth--- (please note, a parsec is a measure of distance, not time, no matter--- what [some ruggedly-handsome ex-carpenter](https://en.wikipedia.org/wiki/Han_Solo)--- might claim). The downloaded file is called--- @gaia-aa-616-a10-table1a.no-header.tsv@, although I have--- manually edited it to a \"more standard\" TSV form (we Astronomers like--- our metadata, and tend to stick it in inappropriate places, such as the--- start of comma- and tab-separated files, which really mucks up--- other-people's parsing code). The first few rows in the file are:--------- +-------------------+---------+-----------+-----------+--------+--------+-------+--- | Source            | Cluster | RA_ICRS   | DE_ICRS   | Gmag   | plx    | e_plx |--- +===================+=========+===========+===========+========+========+=======+--- | 49520255665123328 | Hyades  | 064.87461 | +21.75372 | 12.861 | 20.866 | 0.033 |--- +-------------------+---------+-----------+-----------+--------+--------+-------+--- | 49729231594420096 | Hyades  | 060.20378 | +18.19388 | 5.790  | 21.789 | 0.045 |--- +-------------------+---------+-----------+-----------+--------+--------+-------+--- | 51383893515451392 | Hyades  | 059.80696 | +20.42805 | 12.570 | 22.737 | 0.006 |--- +-------------------+---------+-----------+-----------+--------+--------+-------+--- | ...               | ...     | ...       | ...       | ...    | ...    | ...   |--- +-------------------+---------+-----------+-----------+--------+--------+-------+------ The @Source@ column is a numeric identifier for the star in the Gaia database,--- in this particular case the [\"DR2\" release](https://www.cosmos.esa.int/web/gaia/dr2),--- the @Cluster@ column tells us which [Star Cluster](https://en.wikipedia.org/wiki/Star_cluster)--- the star belongs to, @RA_ICRS@ and @DE_ICRS@--- [locate the star on the sky](https://en.wikipedia.org/wiki/Celestial_coordinate_system)--- and use the [Equatorial coordinate system](https://en.wikipedia.org/wiki/Equatorial_coordinate_system)--- (the @ICRS@ term has a meaning too, but it isn't important for our--- purposes),--- @Gmag@ measues the "brightness" of the star (as in most-things Astronomical,--- this is not as obvious as you might think, as I'll go into below),--- and the @plx@ and @e_plx@ columns give the measured--- [parallax of the star](https://en.wikipedia.org/wiki/Equatorial_coordinate_system)--- and its error value, in units of--- milli [arcseconds](https://en.wikipedia.org/wiki/Minute_and_second_of_arc).--- And yes, I do realise after complaining about popular-culture references--- confusing distances and time, I am now measuring distances with angles.--- I think I've already mentioned that Astronomy is confusing...---- $output--- The function 'toVegaLite' takes a list of grammar specifications,--- as will be shown in the examples below, and creates a single JSON object--- that encodes the entire design. As of @hvega-0.4.0.0@ this targets--- version 3 of the Vega-Lite schema, but this can be over-ridden with--- 'toVegaLiteSchema' if needed.------ There is no concept of ordering to these specification lists, in that--- @[ dataFromUrl ..., encoding ..., mark ...]@;--- @[ encoding ..., dataFromUrl ..., mark ... ]@;--- and--- @[ encoding ..., mark ..., dataFromUrl ... ]@--- would all result in the same visualization.------ The output of 'toVegaLite' can be sent to the Vega-Lite runtime to--- generate the Canvas or SVG output. @hvega@ contains the helper--- routines:------  * 'fromVL', which is used to extract the JSON contents from 'VegaLite'---    and create an Aeson 'Data.Aeson.Value';------  * 'toHtml', which creates a HTML page which uses the---    <https://github.com/vega/vega-embed Vega Embed> Javascript---    library to display the Vega-Lite visualization;------  * and 'toHtmlFile', which is like 'toHtml' but writes the output---    to a file.---- $singleview-stripplot--- In this section we shall concentrate on creating a single--- plot. Later on we shall try combining plots, after branching--- out to explore some of the different ways to visualize--- multi-dimensional data sets. ------ In the examples I link to symbols that have not been used in--- previous visualizations, to make it easier to see the use--- of new functionality.--{-|--We could encode one of the numeric data fields as a strip plot where-the horizontal position of a tick mark is determined by the value-of the data item. In this case I am going to pick the "@plx@" column:--<<images/vl/stripplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CmBIdABPDgVmPIKAX0JWoqgAEi5sDLhmNk4efndkiSlZEUwVXj6Bh3H-BklLawBmEQArLnVCwkgtVSJMNTFqyAAPS5LMBQYiZg4GG7wMBqa0SABHWlgNJJSJhbJBWp1Dqo1HcLmhgO1WkA Open this visualization in the Vega Editor>--@-'toVegaLite'-    [ 'dataFromUrl' "https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv" ['TSV']-    , 'mark' 'Tick' []-    , 'encoding' ('position' 'X' [ 'PName' "plx", 'PmType' 'Quantitative' ] [])-    ]-@--Notice how there is __no explicit definition__ of the axis details,-color choice or size. These can be customised, as shown in examples-below, but the default values are designed to follow good practice in-visualization design.--Three grammar elements are represented by the three functions-'dataFromUrl', 'mark', and 'encoding'.--The 'encoding' function takes as a single parameter, a list of-specifications that are themselves generated by other functions. In-this case we use the function 'position' to provide an encoding of the-@\"plx\"@ field as the x-position in our plot. The precise way in which-the data value (parallax) is mapped to the x-position will depend on the type of-data we are encoding. We can provide a hint by delcaring the-measurement type of the data field, here 'Quantitative' indicating a-numeric measurement type. The final parameter of position is a list of-any additional encodings in our specification. Here, with only one-encoding, we provide an empty list.--As we build up more complex visualizations we will use many more-encodings. To keep the coding clear, the idiomatic way to do this with-hvega is to chain encoding functions using point-free-style. The example above coded in this way would be--@-let enc = encoding-            . position X [ PName "plx", PmType Quantitative ]--in toVegaLite-    [ dataFromUrl "https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]-    , mark Tick []-    , enc []-    ]-@---}--stripPlot :: VegaLite-stripPlot = toVegaLite-    [ dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]-    , mark Tick []-    , encoding (position X [ PName "plx", PmType Quantitative ] [])-    ]---- $background-note--- The default background color for the visualization, at least in the--- Vega-Embed PNG and SVG output, is transparent. In many cases this is--- perfectly fine, but an explicit color can be specified using the--- 'Background' configuration option.--{-|--The 'configure' function allows a large number of configuration-options to be configured, each one introduced by the-'configuration' function. Here I set the color to be a light gray-(actually a very-transparent black; the 'Color' type describes the-various supported color specifications, but it is generally safe to assume-that if you can use it in HTML then you can use it here).--<<images/vl/stripplotwithbackground.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEDGD2B2AzAlgc0gLjMSAjAhtANaoBOsArvACaZSmoEAUADADRjuccsB0AjAEpIAXzbgoAW3ykidSABdkxSOIiRq+BfjqgI6iqQA28gBYKFABwDOGAPR3S+AO69UyBaYq4K1gKakcPAKfsG8cJJ2ACKUqABChkR+dqYAbn6o+HbS1iGkKemZdpradpnI+AC0+FUAbPy11fwsldq4Rn78+LzwsJWmfvjUAbwK1qmqEuqIsKTSCrqKAJ6WfvJjEyISYhKQACTW0APSZhY29naF3e6e3rzIsHaHx1lXlUYeyakAzLwAVtYEJN1KE4NRkPB0FgcAAPRYoPxGWhYSCWIxwjjLVbyACOFHwwQ8WmQ6VEWxEQA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"plx\", PmType Quantitative ]--    conf = 'configure'-             . 'configuration' ('Background' "rgba(0, 0, 0, 0.1)")--in toVegaLite-    [ dataFromUrl \"https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv\" [TSV]-    , mark Tick []-    , enc []-    , conf []-    ]-@---}--stripPlotWithBackground :: VegaLite-stripPlotWithBackground = toVegaLite-    [ dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]-    , mark Tick []-    , encoding (position X [ PName "plx", PmType Quantitative ] [])-    , configure (configuration (Background "rgba(0, 0, 0, 0.1)") [])-    ]---{-|-There is nothing that forces us to use the x axis, so let's-try a vertical strip plot. To do so requires changing only-__one__ character in the specifiction, that is the first argument to-'position' is now 'Y' rather than 'X':--<<images/vl/stripploty.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CmBIdABPDgVmPIKAX0JWoqgAEi5sDLhmNk4efndkiSlZEUwVXj6Bh3H-BklLawBmEQArLnVCwkgtVSJMNTFqyDrLkswFBiJmDgYAD0KMBqa0SABHWlgNJJSJhbJBWp1Dqo1LcLmhgO1WkA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position 'Y' [ PName "plx", PmType Quantitative ]--in toVegaLite-    [ dataFromUrl \"https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv\" [TSV]-    , mark Tick []-    , enc []-    ]-@--}-stripPlotY :: VegaLite-stripPlotY = toVegaLite-    [ dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]-    , mark Tick []-    , encoding (position Y [ PName "plx", PmType Quantitative ] [])-    ]---{-|-Since we are going to be using the same data source, let's define it here:--@-gaiaData =-  let addFormat n = (n, 'FoNumber')-      cols = [ \"RA_ICRS\", \"DE_ICRS\", \"Gmag\", \"plx\", \"e_plx\" ]-      opts = [ 'Parse' (map addFormat cols) ]--  in dataFromUrl "https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv" opts-@--The list argument to 'dataFromUrl' allows for some customisation of-the input data.  Previously I used @['TSV']@ to specify the data is in-tab-separated format, but it isn't actually needed here (since the-file name ends in \".tsv\"). However, I have now explicitly defined how-to parse the numeric columns using 'Parse': this is because the columns-are read in as strings for this file by default, which actually doesn't-cause any problems in most cases, but did cause me significant problems-at one point during the development of the tutorial! There is limited-to no feedback from the visualizer for cases like this (perhaps I should-have used the Javascript console), and I only realised the problem thanks-to the @Data Viewer@ tab in the-<https://vega.github.io/editor/#/ Vega Editor>-(after a-<https://twitter.com/pkgw/status/1167127390880968707 suggestion from a colleague>).--Although not used in this tutorial, data-can also be defined algorithmically - using 'dataSequence' and-'dataSequenceAs' - or inline - with 'dataFromColumns' or-'dataFromRows' - or directly from JSON (as a 'Data.Aeson.Value') using-'dataFromJson'.---}--gaiaData :: Data-gaiaData =-  let addFormat n = (n, FoNumber)-      cols = [ "Gmag", "plx", "e_plx" ]-      opts = [ Parse (map addFormat cols) ]--  in dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" opts---{-|--One question would be how the parallaxes vary by cluster: as parallax is measuring distance,-then are the clusters similar distances away from us, or are there a range of values? A-first look is to use another \"channel\" to represent (i.e. encode) the cluster:--<<images/vl/stripplotwithcolor.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CmBIDgRFasgAcTgxZjVaaBklQqgOBgAPds7u+F7IBQB9fqG0SA6unoBfJcIloqgAEi5sDLhmNk4efndkiSlZEUwVXh29h1P-BklLawBmEQArLnVCwgm1KoiJg1G00FRqJBVAxyo0SpgFAwiMwAMIMeQucboACeHAU7RU0BBsCY60INFmlHJkPhiORcxmf2KNBxeOYAEdaLANJJSJhbEzmZBYANMFxGlh0AlmAAFBAkhgisAACicAEpIKtilqwGSaKo1PCwZRVksgA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"plx\", PmType Quantitative, 'PAxis' [ 'AxTitle' \"Parallax (mas)\" ] ]-            . 'color' [ 'MName' \"Cluster\", MmType 'Nominal' ]--in toVegaLite-    [ gaiaData-    , mark Tick []-    , enc []-    ]-@--Now each tick mark is colored by the cluster, and a legend is automatically-added to indicate this mapping. Fortunately the number of clusters in the-sample is small enough to make this readable! The 'color' function has-added this mapping, just by giving the column to use (with 'MName') and-its type ('MmType'). The constructors generally begin with @P@ for-position and @M@ for mark, and as we'll see there are other property-types such as facet and text.--Vega-Lite supports several data types, represented-by the 'Measurement' type. We have already seen 'Quantitative', which-is used for numeric data, and here we use 'Nominal' for the clusters,-since they have no obvious ordering.--The labelling for the X axis has been tweaked using 'PAxis', in this-case the default value for the label (the column name) has been-over-ridden by an explicit value.---}--stripPlotWithColor :: VegaLite-stripPlotWithColor =-  let enc = encoding-            . position X [ PName "plx", PmType Quantitative, PAxis [ AxTitle "Parallax (mas)" ] ]-            . color [ MName "Cluster", MmType Nominal ]--  in toVegaLite-     [ gaiaData-     , mark Tick []-     , enc []-     ]----- $stripplot-mmtype--- It is instructive to see what happens if we change the mark type for--- the color encoding from 'Nominal' to 'Ordinal'.--{-|--<<images/vl/stripplotwithcolorordinal.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CmBIDgRFasgAcTgxZjVaaBklQqgOBgAPds7u+F7IBQB9fqG0SA6unoBfJcIloqgAEi5sDLhmNk4efndkiSlZEUwVXh29h1P-BklLawBmEQArLnVCwgm1KoiJg1G00FRqJBVAxyo0SpgFAwiMwAMIMeQucboACeHAUzHKwLUsCY60INFmlHJkPhiORcxmf2KNBxeOYAEdaLANJJSJhbEzmZBYANMFxGlh0AlmAAFBAkhgisAACicAEpIKtilqwGSaKo1PCwZRVksgA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"plx\", PmType Quantitative, PAxis [ AxTitle \"Parallax (mas)\" ] ]-            . color [ MName \"Cluster\", MmType 'Ordinal' ]--in toVegaLite-    [ gaiaData-    , mark Tick []-    , enc []-    ]-@--As can be seen, the choice of color scale has changed to one more-appropriate for an ordered set of values.--}-stripPlotWithColorOrdinal :: VegaLite-stripPlotWithColorOrdinal =-  let enc = encoding-            . position X [ PName "plx", PmType Quantitative, PAxis [ AxTitle "Parallax (mas)" ] ]-            . color [ MName "Cluster", MmType Ordinal ]--  in toVegaLite-     [ gaiaData-     , mark Tick []-     , enc []-     ]---- $add-axis--- While the strip plot shows the range of parallaxes, it is hard to--- make out the distribution of values, since the ticks overlap. Even--- changing the opacity of the ticks - by adding an encoding channel--- like @'opacity' [ 'MNumber' 0.6 ]@, or by setting the 'MOpacity'--- property of the 'mark' - only helps so much. Adding a second--- axis is easy to do, so let's see how the parallax distribution--- varies with cluster membership.---{-|--The 'stripPlotWithColor' visualization can be changed to show two-variables just by adding a second position declaration:--<<images/vl/parallaxbreakdown.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CmBIDgRFasgAcTgxZjVaaBklQqgOBgAPds7u+F7IBQB9fqG0SA6unoBfJcIloqgAEi5sDLhmNk4efndkiSlZEUwVXh29h1P-BklLawBmEQArLnVCwgm1KoiJg1G00FRqJBVAxyo0SpgFAwiMwAMIMeQucboACeHAU7RU0BBsCY60INFmlHJkPhiORcxmf2KNBxeOYAEdaLANJJSJhbEzmZBYANMFxGlh0AlmAAFBAkhgisAACicAEpIKtimTipBsXCEUjUejnD08Bhcfi5qkiWoSZq1hsoep4WDKKslkA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"plx\", PmType Quantitative, PAxis [ AxTitle \"Parallax (mas)\" ] ]-            . position Y [ PName \"Cluster\", PmType Nominal ]-            . color [ MName \"Cluster\", MmType Nominal ]--in toVegaLite-    [ gaiaData-    , mark Tick []-    , enc []-    ]-@--I have left the color-encoding in, as it makes it easier to compare to-'stripPlotWithColor', even though it replicates the information provided-by the position of the mark on the Y axis.---}--parallaxBreakdown :: VegaLite-parallaxBreakdown =-  let enc = encoding-            . position X [ PName "plx", PmType Quantitative, PAxis [ AxTitle "Parallax (mas)" ] ]-            . position Y [ PName "Cluster", PmType Nominal ]-            . color [ MName "Cluster", MmType Nominal ]--  in toVegaLite-     [ gaiaData-     , mark Tick []-     , enc []-     ]----- $histogram--- We can also \"create\" data to be plotted, by aggregating data. In this--- case we can create a histogram showing the number of stars with the--- same parallax value (well, a range of parallaxes).--{-|--Since sensible (hopefully) defaults are provided for unspecified settings, it-is relatively easy to write generic representations of a particular-visualization. The following function expands upon the previous-specifications by:-- * taking a field name, rather than hard coding it;-- * the use of @'PBin' []@ to ask for the x-axis values to be binned;-- * the addition of a second axis ('Y') which is used for the-   aggregated value ('Count', which means that no column has-   to be specified with @PName@);-- * and the change from 'Tick' to 'Bar' for the 'mark'.--Note that we did not have to specify how we wanted the histogram-calculation to proceed - e.g. the number of bins, the bin widths,-or edges - although we could have added this, by using a non-empty-list of 'BinProperty' values with 'PBin', if the defaults are not-sufficient.--@-simpleHistogram field =-  let enc = encoding-              . position X [ PName field, PmType Quantitative, 'PBin' [] ]-              . position Y [ 'PAggregate' 'Count', PmType Quantitative ]--  in toVegaLite-       [ gaiaData-       , mark 'Bar' []-       , enc []-       ]-@---}--simpleHistogram :: T.Text -> VegaLite-simpleHistogram field =-  let enc = encoding-              . position X [ PName field, PmType Quantitative, PBin [] ]-              . position Y [ PAggregate Count, PmType Quantitative ]--  in toVegaLite-     [ gaiaData-     , mark Bar []-     , enc []-     ]  --{-|--With 'simpleHistogram' it becomes easy to get a histogram of the parallax-values:--<<images/vl/parallaxhistogram.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMmBINgR5SsgAcTgRRlVqaHQFHCg2OgAPVvbO+G7IOQB9XoG0SDaOroBfBbwF3CoAEg5FdLhGFnYuXjck8UlpITFlbi2d+2O-OgkLKwBmIQArDjUCqk0VfDEqhaaAolEg03IkCKYjkdHwjCmo3QgLIRHg1Dk2CgRAAnmw5IwAI7UWDqCTEMQ2SCrQpQHH1WAiETwWzEAkzFTUdSjXH4okkskkIiUgnLCA0qgqVTQ4HkZYLIA Open this visualization in the Vega Editor>--@parallaxHistogram = 'simpleHistogram' \"plx\"@--We can see that although parallaxes around 20 to 25 milli-arcseconds-dominated the earlier visualizations, such as 'stripPlotWithColor',-__most__ of the stars have a much-smalled parallax, with values-in the range 5 to 10.---}---- TODO XXX explain parallax--parallaxHistogram :: VegaLite-parallaxHistogram = simpleHistogram "plx"--{-|--A different column (or field) of the input data can be viewed,-just by changing the name in the specification:--<<images/vl/gmaghistogram.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMmBINgR5SsgAcTgRRlVqaHQFHCg2OgAPVvbO+G7IOQB9XoG0SDaOroBfBbwF3CoAEg5FdLhGFnYuXjck8UlpITFlbi2d+2O-OgkLKwBmIQArDjUCqk0VfDEqhaaAolEg03IkCKYjkdHwjCasBa2AwgLIRHg1DkKMgRAAnmw5IwAI7UWDqCTEMQ2SCrQpQPH1JEieC2YhEmYqajqUb4wkkskUkhEalE5YQOlUFSqaHA8jLBZAA Open this visualization in the Vega Editor>--@gmagHistogram = simpleHistogram \"Gmag\"@--Here we can see that the number of stars with a given magnitude-rises up until a value of around 18, and then drops off.---}---- TODO XXX explain magnitudes--gmagHistogram :: VegaLite-gmagHistogram = simpleHistogram "Gmag"------ $ylog-histogram--- In the case of 'parallaxHistogram', the data is __dominated__ by--- stars with small parallaxes. Changing the scale of the--- Y axis to use a logarithmic, rather than linear, scale /might/--- provide more information:--{-|--<<images/vl/yloghistogram.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZjCQDOK5A9pbDZIuaQJ6T5QAZvAA2Ijs24A7ROwGQUPAA7tMkAEYVIAX0IRIAE1IpSNUBH0BXcuLWoUS+ugD0z7gHcAdIngpol9Ut6WHIAY2YpFFhIz3DiZwARZktEACFrNmdoADdYRFJnMkYQrNz85yMTZ3z4UgBaUnqANgBGJoaWnDqTdRFYFtJPKWY6uFIDEM8Uemz+In1BSTI0TDolCmCzSABxMkQOKUtidRD+KCURAA8Do5PyM8hYAH0L67VD49PtbSJdIkgACT0UJwMgceyOFzOMqDHx+AKeeDMZzA0EFGF1ES+WDQrCeABW9Aic30KF8fQ421ItTAAAUKKQxKRLrB6CSoNFwgZ4DIzPMoG9aPyFvBYCIDBxXuyLFB1DyaExLLA9DKoIoVBwAI6WUiRXzGeC5aUWSDM+Bs1YKcmqKD07hMy5gAAURQAlDp+X8ZZA+KthVBgYybXR1TbICJmPsvarTYguHljGHwpZIsbScow9rdWSTGSjZ7firIOEpMJ9qsftogA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName "plx", PmType Quantitative, PBin [], PAxis [ AxTitle "Parallax (mas)" ] ]-            . position Y [ PAggregate Count, PmType Quantitative, 'PScale' [ 'SType' 'ScLog' ] ]--in toVegaLite-   [ gaiaData-   , mark Bar [ 'MFill' "orange", 'MStroke' "gray" ]-   , enc []-   , 'height' 300-   , 'title' "Gaia Parallaxes" []-   ]  -@--There are four new changes to the visualization created by 'simpleHistogram' (since 'PAxis'-has been used above):-- 1. an explicit choice of scaling for the Y channel (using 'PScale');-- 2. the fill ('MFill') and edge ('MStroke') colors of the histogram bars are different;-- 3. the height of the overall visualization has been increased;-- 4. and a title has been added.--If you view this in the Vega Editor you will see the following warning:--@-A log scale is used to encode bar's y. This can be misleading as the height of the bar can be arbitrary based on the scale domain. You may want to use point mark instead.-@---}-ylogHistogram :: VegaLite-ylogHistogram =-  let enc = encoding-              . position X [ PName "plx", PmType Quantitative, PBin [], PAxis [ AxTitle "Parallax (mas)" ] ]-              . position Y [ PAggregate Count, PmType Quantitative, PScale [ SType ScLog ] ]--  in toVegaLite-     [ gaiaData-     , mark Bar [ MFill "orange", MStroke "gray" ]-     , enc []-     , height 300-     , title "Gaia Parallaxes" []-     ]  ---{-|--A color encoding can also be added. When used with the 'Tick' mark --'stripPlotWithColor' - the result was that each tick mark was colored-by the \"Cluster\" field, but for the 'Bar' mark the result is that-the bars are stacked together. I have also taken the opportunity to-widen the plot ('width'); define the binning scheme used, with @'Step'-1@; and configure the location of the x axis tick marks, using-'AxValues'.--<<images/vl/gmaghistogramwithcolor.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQBGFkhEkAJqSqTaBMwK7kAbGjBQoADgGd0AemnlSAdwB0ieCmi9avCbHIBjAPYA7FLBNLDxaQBEDvRACF+lWNOgA3WIlLSyE0+Runt7SbBzS3vCkALSkMQBsAIzxsYk40Ry0ArCJpEpGBtFwpCy6SigS7oxEzABmBuRkaJjAkGIUOlyQAOJkiMJGvMS0uoxQYgIAHgNDI+RjkLAA+hPTmJCDw6MAvttE20xQCvAs6jQALHiHkAAkEnpwZMKo4lKywXmq6ppK8AbS90ePg+0QEalc7iwSgAVhJjNVmGZDCx4EZ+i0alBDAIGl1avBYAIWMIAMICbQBBYoACeYlgAwMxFRpCEB0xkDWYG4PDqBKJwl6pH6hx5kFoqK6-lgYhoiTZPOYNLpwgAjrxSCY1Ox4J4EQrIKRJvAJF13CzeLATZgANoEMAAVnwYDSTsSjrAACYcABdPY8+U8SDUrpCxDkLzsenrQy8ExU2lRqBqjUoLWp3V+sAByCGIz49FcvbbIA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"Gmag\", PmType Quantitative, binning, axis ]-            . position Y [ PAggregate Count, PmType Quantitative ]-            . color [ MName \"Cluster\", MmType Nominal ]--    binning = PBin [ 'Step' 1 ]-    axis = PAxis [ 'AxValues' ('Numbers' [ 0, 5 .. 20 ]) ]-    -in toVegaLite-   [ gaiaData-   , mark Bar []-   , enc []-   , height 300-   , 'width' 400-   ]  -@--Note that @hvega@ will allow you to combine a 'color' encoding with a 'ScLog'-scale, even though a Vega-Lite viewer will not display the-resulting Vega-Lite specification, saying--@Cannot stack non-linear scale (log)@---}-gmagHistogramWithColor :: VegaLite-gmagHistogramWithColor =-  let enc = encoding-              . position X [ PName "Gmag", PmType Quantitative, binning, axis ]-              . position Y [ PAggregate Count, PmType Quantitative ]-              . color [ MName "Cluster", MmType Nominal ]--      binning = PBin [ Step 1 ]-      axis = PAxis [ AxValues (Numbers [ 0, 5 .. 20 ]) ]-      -  in toVegaLite-     [ gaiaData-     , mark Bar []-     , enc []-     , height 300-     , width 400-     ]  --{-|--Notice how we never needed to state explicitly that we wished our bars-to be stacked. This was reasoned directly by Vega-Lite based on the-combination of bar marks and color channel encoding. If we were to-change just the mark function from 'Bar' to 'Line', Vega-Lite produces an-unstacked series of lines, which makes sense because unlike bars,-lines do not occlude one another to the same extent.--<<images/vl/gmaglinewithcolor.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQA28AdrJIRJACakqk2gRsBXcrRowUKAA4BndAHpZ5UgHcAdIngpoAgEYCpscgGMA9gxSwzKk8VkARYwMQAhIZVizoAN1iJSsslLm5B7evrKc3LK+8KQAtKRxAGwAjInxyTix3Nq0sMmkKgzGsXCk7AYqKFKeLERsAGbG5GRomMCQEhT6vJAA4mSIogwCxNoGLFAStAAeQyNj5BOQsAD6U7OYkMOj4wC+u0S7rFBK8OyaNAAseMeQACRShnBkoqiSMvKhBeqaOirwxlkj2efi+sXo5lkniwKgAVlJTLU2BYTOxGIM2nUoCZaE0evV4LBaOxRABhWh6IJLFAATwkzE2RWIjFIIiOWMgGzAfH4DUJxNE-VIg2OvMg2kYPUCsAkNGS7N5bFp9NEAEcBKQzBouPBvEjFZBSNN4FIep5WQJYKbMABtAhgACs+DAGWdySdYAATDgALoHXkK-iQGk9YWIcg+LgM7EOMzUunRyDqzUobWpvX+sCByAmBgEjHcg67IA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"Gmag\", PmType Quantitative, binning, axis ]-            . position Y [ PAggregate Count, PmType Quantitative ]-            . color [ MName \"Cluster\", MmType Nominal ]--    binning = PBin [ Step 1 ]-    axis = PAxis [ AxValues (Numbers [ 0, 5 .. 20 ]) ]-    -in toVegaLite-   [ gaiaData-   , mark 'Line' []-   , enc []-   , height 300-   , width 400-   ]  -@---}--gmagLineWithColor :: VegaLite-gmagLineWithColor =-  let enc = encoding-              . position X [ PName "Gmag", PmType Quantitative, binning, axis ]-              . position Y [ PAggregate Count, PmType Quantitative ]-              . color [ MName "Cluster", MmType Nominal ]--      binning = PBin [ Step 1 ]-      axis = PAxis [ AxValues (Numbers [ 0, 5 .. 20 ]) ]-      -  in toVegaLite-     [ gaiaData-     , mark Line []-     , enc []-     , height 300-     , width 400-     ]  ----- $histogramChoice--- The previous histogram visualizations have taken advantage of Vega-Lite's--- ability to bin up ('Count') a field, but there are a number of aggregation--- properties (as defined by the 'Operation' type). For example, there--- are a number of measures of the \"spread\" of a population, such as--- the sample standard deviation ('Stdev').--{-|-The aim for this visualization is to show the spread in the @Gmag@ field-for each cluster, so we now swap the axis on which the aggregate is-being applied (so that the cluster names appear on the y axis),-and hide the legend that is applied (using @'MLegend' []@) since-we can read off the color mapping from the y axis.--<<images/vl/yhistogram.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuMxIHsAOsDGAlgC4CeqYADAHQBsANFKdgKbmQBGCkAvneFABNYRWOVAQIkAK7wANmwAWRItgDOKAPQb4sAO5UA5sQVT2U1c3h5MAOyLM7Va9A0ARTFIMAhGYmYaFADdmA1gNOFV7eADg0I0hEQ1QglgAWlg0mgBGGnSsilSRdllmLNgqG0xUhWZYAUsqIlVAyD4JKAAzTHg4IjFIXHgLfoBxOAM2GylodktWqGxZAA9J6dn4echmAH1FlbRIKZm57m5+Xn5IABJVPBq4RWU1TQ1Y8qMiE3YqAkwNW-uYTeqVkxH8gQAzFQAFaqWytS4OawCAg2CZocQSSDWWTdfodAjMWQCNgAYVk5iimyYrAOlWgqNg8gYkBKBgcJLQU1ksgu7Ug+3QkAJRM5UDGsAmLMlBngIWEtKgkXqLRZNLYAEcpLA7MRhARgjw2liyBjhYTiWSKZE5mqSCxJpgGTYmTxzsbsbYCej0GduEA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"Gmag\", PmType Quantitative, PAggregate 'Stdev' ]-            . position Y [ PName \"Cluster\", PmType Nominal ]-            . color [ MName \"Cluster\", MmType Nominal, 'MLegend' [] ]--in toVegaLite-   [ gaiaData-   , mark Bar [ 'MOpacity' 0.6 ]-   , enc []-   ]  -@--The bar opacity is reduced slightly with 'MOpacity 0.6' so that the-x-axis grid lines are visible. An alternative would be to change the-'AxZIndex' value for the 'X' encoding so that it is drawn on top of-the bars.---}--yHistogram :: VegaLite-yHistogram =-  let enc = encoding-              . position X [ PName "Gmag", PmType Quantitative, PAggregate Stdev ]-              . position Y [ PName "Cluster", PmType Nominal ]-              . color [ MName "Cluster", MmType Nominal, MLegend [] ]--  in toVegaLite-     [ gaiaData-     , mark Bar [ MOpacity 0.6 ]-     , enc []-     ]  -  ----- $intro-points--- At this point we make a signifiant detour from the Elm Vega-Lite--- walkthtough, and look at the 'Point' mark, rather than creating--- small-multiple plots. Don't worry, we'll get to them later.--{-|--Here I use the 'Point' mark to display the individual-@Gmag, plx@ pairs, encoding by __both__ 'color' and 'shape.-Since the encoding uses the same field of the data (the @Cluster@-name), Vega-Lite is smart enough to only display one legend,-which contains the point shape and color used for each cluster.--Since the parallax values are bunched together at low values,-a logarithmic scale ('ScLog') is used for the y axis, along with-commands to define the actual axis domain - by turning off the-'IsNice' support and listing the minimum and maximum values-for the axis with 'SDomain'.--<<images/vl/pointplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMAWADDgNOFALYCGATgNYZQAOA9vAHZqESQAmpKpNoE7AK7kANjRgoUtAM7oA9HPKkA7gDpE8FNEEAjQdNjkAxvRawWqk8TkAReoMQAhYZVhzoAN1iJScstJRDdy8fOS4eOR94UgBaUliANgBGBLiknBieHRFYJNJVJnoYuFIOQ1UUaQ9INgFIADN6cjI0TGBIWgoDPkgAcTJEcSZBYh1DGroRAA8hkbHyCchYAH1aadnR8YBfLaIt2shleA4tGlwCIkgAEmkjODJxVClZBRD8jS1dVXh6OVv73xvGIiTRuDwAZlUACtpKYapdzCYOMxBm0iOwTCImj16vBYCIOOIAMIifSBBb4KAoACetFgQ3oxGYpDE+3RUGk0FIdJxeIJxNJAXGlMgNJ5mEghSZTBZkDZAigMzaDT5hIl-VIgxFYvpEoAjoJSCxNNx4F45bV2NS+Oz2Lj8WrJjNLXVbizdWB2hxGaRmDQANqQgCslPBACYALra2keyBYrVQJjwIwe+osgzyhVUmPiA1GlAmgvm9m7CCZyAmJi41Ge3ZbIA Open this visualization in the Vega Editor>--@-let enc = encoding-                    . position X [ PName \"Gmag\", PmType Quantitative ]-                    . position Y [ PName \"plx\", PmType Quantitative, PScale scaleOpts ]-                    . color cluster-                    . shape cluster--    scaleOpts = [ SType ScLog, 'SDomain' ('DNumbers' [3.5, 32]), 'SNice' ('IsNice' False) ]-    cluster = [ MName \"Cluster\", MmType Nominal ]--in toVegaLite [ gaiaData-              , mark 'Point' []-              , enc []-              , width 400-              , height 400-              ]-@--We can see that each cluster appears to have a separate parallax-value, and that it doesn't really vary with Gmag. What this is telling-us is that for these star clusters, the distance to each member star-is similar, and that they are generally at different distances-from us. However, it's a bit hard to tell exactly what is going-on around 5 to 6 milli arcseconds, as the clusters overlap here.--This line of thinking leads us nicely to map making, but before we-try some cartography, I wanted to briefly provide some context for-these plots. The-<https://lco.global/spacebook/distance/parallax-and-distance-measurement/ parallax of a star>-is a measure of its distance from us, but it is an inverse relationship,-so that nearer stars have a larger parallax than those further from us.-The @Gmag@ column measures the apparent brightness of the star, with the-@G@ part indicating what-<https://www.cosmos.esa.int/web/gaia/iow_20180316 part of the spectrum>-is used (for Gaia, the @G@ band is pretty broad, covering much of-the visible spectrum), and the @mag@ part is because optical Astronomy-tends to use-- * <https://www.skyandtelescope.com/astronomy-resources/the-stellar-magnitude-system/ the logarithm of the measured flux>-- * and then subtract this from a constant--so that larger values mean fainter sources. These are also-<https://en.wikipedia.org/wiki/Apparent_magnitude apparent magnitues>,-so that they measure the flux of the star as measured at Earth,-rather than its intrinsic luminosity (often defined as an object's-<https://en.wikipedia.org/wiki/Absolute_magnitude absolute magnitude>).--We can see that the further the cluster is from us - that is, as we-move down this graph to smaller parallax values - then the-smallest stellar magnitude we can see in a cluster tends to increase,-but that there are stars up to the maximum value (20) in each cluster.-This information can be used to look at the-distribution of absolute magnitudes of stars in a cluster, which-tells us about its evolutionary state - such as is it newly formed or old --amongst other things. However, this is straying far from the-aim of this tutorial, so lets get back to plotting things.---}--pointPlot :: VegaLite-pointPlot =-  let enc = encoding-              . position X [ PName "Gmag", PmType Quantitative ]-              . position Y [ PName "plx", PmType Quantitative, PScale scaleOpts ]-              . shape cluster-              . color cluster--      scaleOpts = [ SType ScLog, SDomain (DNumbers [3.5, 32]), SNice (IsNice False) ]-      cluster = [ MName "Cluster", MmType Nominal ]-      -  in toVegaLite [ gaiaData-                , mark Point []-                , enc []-                , width 400-                , height 400-                ]---- $intro-map--- We have some hint that the different clusters are distinct objects--- in space, in that they appear to be different distances from us,--- but where does the \"cluster\" in the name \"Stellar Cluster\"--- come from? Well, we can try plotting up the position of each star--- on the sky - using the @RA_ICRS@ and @DE_ICRS@ fields - to find out.--{-|--The following specification should only contain one new feature - other-than sneakily switching from 'Point' to 'Circle' type for the mark - and-that is displaying the x axis (namely Right Ascension) in reverse (using-@'PSort' [ 'Descending' ]@. This is needed because Right Ascension-is measured from right to left. I like to explain it by talking about-oranges, and how we are at the center of an orange looking out at its-skin, and so have the direction reversed to if you were outside, looking-in. You can see that we also have one cluster that straddles the-0 and 360 degrees Right Ascension barrier, which will lead to some-fun later.--<<images/vl/posplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQDG85tANrJIRJACakqk2gQOAV3JMaMFCgAOAZ3QB6eeVIB3AHSJ4KaEIBGQmbEYB7AHYpY5tbWPF5AEWNDEAIRGVY86ADdYiUvJkMhbkXr7+8ty88v7wpAC0pAkAbACMyYmpOPG8uiyppGqmxvFwpJxGaigy3mxEHABmxuRkaJjAkFIUhvyQAOJkiOKmQsS6RmxQUkwAHsOj4+STkLAA+tNzmJAjYxMAvntEe+xQKvCc2jQALHgnkAAkMrRwZOKo0nKK4YWa2npq8GM8ieLwC33iTC0nm8WDUACsZGY6hxLDZOPBTEN2vU6MYmM1eg14LAmJxxABhJgGELLFAATykrC2xWIGNIYmOOMgmzAAkEjWJpPEACUAIKrACS5OFAGVkfyoE92UzeVxbKQMTQANoEbDJHAAXXwUFM8FoKoa7MMnIViuabSgFSelnRmPl-Mg9MZ4gAjkJSOYtDx4L53YJIKQZvAZL0UFoWCKkKgwKLnaYZIDTGAABQVRAASkgh35NvDdP4OIFJLJW3sAFFJdK5ScPUqE+01WRNZgtfEAJy6gdGk1mi1W2Clj1elWQP0BuO8OOhlvhyPR2Pxmf2WDMNlxsw5vOF4uCE+lyA2UxErG8w57IA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X (axOpts \"RA_ICRS\" \"Right Ascension (deg)\" ++ [ raScale, 'PSort' [ 'Descending' ] ])-            . position Y (axOpts \"DE_ICRS\" \"Declination (deg)\" ++ [ decScale ])-            . color [ MName \"Cluster\", MmType Nominal ]-                    -    axOpts field lbl = [ PName field, PmType Quantitative, PAxis [ AxTitle lbl ]]-            -    scaleOpts minVal maxVal = [ SDomain (DNumbers [ minVal, maxVal ]), SNice (IsNice False) ]-    raScale = PScale (scaleOpts 0 360)-    decScale = PScale (scaleOpts (-90) 90)-            -in toVegaLite [ gaiaData-              , mark 'Circle' []-              , enc []-              , width 400-              , height 300-              ]-@--We can see that these clusters are indeed localised on the sky,-with <https://en.wikipedia.org/wiki/Hyades_(star_cluster) Hyades>-looking like it covers the largest area. However, we should be-careful and __not forget__ either -<https://www.youtube.com/watch?v=E9IuXEwpU7U Grover's hard work>-or-<https://www.youtube.com/watch?v=MMiKyfd6hA0 Father Ted's explanation to Father Dougal>,-since these clusters are different distances from us, which-makes size a tricky thing to measure from this plot.--There is also the fact that I have used possibly the worst-way of displaying the Right Ascension and Declination data. Although-the night sky is not the same as the Earth's surface, the issues-when trying to display the Globe on a flat surface also apply to-displaying up the sky. For this plot the distortions near the-pole are huge, although fortunately we don't have any clusters-too close to either pole.---}--posPlot :: VegaLite-posPlot =-  let enc = encoding-              . position X (axOpts "RA_ICRS" "Right Ascension (deg)" ++ [ raScale, PSort [ Descending ] ])-              . position Y (axOpts "DE_ICRS" "Declination (deg)" ++ [ decScale ])-              . color [ MName "Cluster", MmType Nominal ]-                    -      axOpts field lbl = [ PName field, PmType Quantitative, PAxis [ AxTitle lbl ]]-            -      scaleOpts minVal maxVal = [ SDomain (DNumbers [ minVal, maxVal ]), SNice (IsNice False) ]-      raScale = PScale (scaleOpts 0 360)-      decScale = PScale (scaleOpts (-90) 90)-            -  in toVegaLite [ gaiaData-                , mark Circle []-                , enc []-                , width 400-                , height 300-                ]---{-|-Vega-Lite supports a large number of projections - via the-'Projection' type - which we use below to create-a similar visualization to 'posPlot'. Here I use the-'Longitude' and 'Latitude' channels, along with a-'Mercator' 'projection', to display the data.--The trick in this case is that longitude runs from -180 to 180-degrees, but the data has Right Ascension going from 0-to 360 degrees. We can take advantage of Vega Lite's-__data transformation__ capabilities and create a new-column - which I call @fakeLongitude@ - and is-defined as "180 - Right Ascension". The "expression" support-is essentially a sub-set of Javascript, and the @datum@-object refers to the current row. The new data column-can then be used with the 'Longitude' channel.--<<images/vl/skyplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJ5k8pV4BrAUwBl1EBzAS2gFcATGyAGigDG8ADYD2w+NB75IARgAcABjABaMJ0nssAOgBKAQQD6ASQDCugMqQAvgF1e4KFniwq5SAJawBwng4iQGtDw5KAQAeywwu4AFtDQAA7IuAD0KQgA7tqs0DHsAEbsyDTejFKI0NoC6FgpACLo7EwAQpG0KTEAbjRM8CnOyFKwHd29KUF9vSzwKvAzAGyy87OyiirB+b6y8NqI6CoxNPDcsNrQyJ18jgEY2JKhkAkuxQ8A4s5M7oha+SV8UAlhAAPL4-P78SA0QyAkEyb5YX6wGzWRzWfxQAAkyAEh2csXiSVSKVGOxyeXy2hY6BS2NxfRJKmEbBoxIAzNoAFbIRhXAIJWDoDk0ATQKmIB7QACeCWkThKQmgmBs6MhiGqnBYzFC10E6GESvwYXCNxYNGEnHcMN5xqg2JEsuItJoWFlkE6XhYGrIEKlMvc+s+aJ1AV9roAjuwkKLgqLupAdUHjZAJNGuA7IKhTeb3HUAKImcxWH3S8ORipsSQsOOJ8IwdB60UJB6Zs0WmSmYRFIb-GAlr41TUiZU65OMHJp5tZtsUaj0MdsCfFv0yCNRiuxngoiA1jyMTOfQ0o6xAA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position 'Longitude' (axOpts "fakeLongitude")-            . position 'Latitude' (axOpts \"DE_ICRS\")-            . color [ MName \"plx\"-                    , MmType Quantitative-                    , 'MScale' [ SType ScLog-                             , 'SScheme' \"viridis\" []-                             ]-                    ]-            . 'tooltip' [ 'TName' \"Cluster\", 'TmType' Nominal ]-                  -      axOpts field = [ PName field, PmType Quantitative ]-          -      trans = 'transform'-                . 'calculateAs' "180 - datum.RA_ICRS" "fakeLongitude"-                     -in toVegaLite [ 'projection' [ 'PrType' 'Mercator' ]-              , gaiaData-              , trans []-              , mark Circle []-              , enc []-              ]-@--The other major change made to 'posPlot' is that the stars are now-color-encoded by the log of their parallax value-rather than cluster membership,-and the color scheme has been changed to use the \"viridis\" color-scale.-Since parallax is a numeric value, with ordering (i.e. 'Quantitative'),-the legend has changed from a list of symbols to a gradient bar.-To account for this lost of information, I have added a 'tooltip'-encoding so that when the pointer is moved over a star its cluster-name will be displayed (this replaces the default behavior when-all the encoded channels, so in this case the position and parallax-values, would be displayed, and it is only visible in \"interactive\"-versions of the visualization).--From this visualization we can see that the apparent size of the cluster-(if we approximate each cluster as a circle, then we can think of the radius-of the circle as a measure of size) depends on parallax, with larger-sizes having larger parallaxes. This is because the distance to a star-is inversely-dependent on its parallax, so larger parallaxes mean the-star is closer to us. However, there is no reason that the intrinsic-size - that is its actual radius - of each cluster is the same.-We can see that although the Hyades and Pleiades clusters overlap-on the sky, they have significantly-different parallaxes (as can-be seen in 'pointPlot' for example), with Hyades being the closer-of the two.--It is possible to add graticules - with the aptly-named-'graticule' function - but this appears to need to be done-as a layer, which we haven't covered yet. I may get to it-below, but am having teensy problems with getting it-working in the Vega Lite viewer I use (the one provided with-Jupyter notebook, which defaults to an earlier version-of Vega-Lite support, which doesn't seem to like the more-recent-capabilities of Vega Lite).---}--skyPlot :: VegaLite-skyPlot =-  let enc = encoding-              . position Longitude (axOpts "fakeLongitude")-              . position Latitude (axOpts "DE_ICRS")-              . color [ MName "plx"-                      , MmType Quantitative-                      , MScale [ SType ScLog-                               , SScheme "viridis" []-                               ]-                      ]-              . tooltip [ TName "Cluster", TmType Nominal ]-                    -      axOpts field = [ PName field, PmType Quantitative ]-            -      trans = transform-                . calculateAs "180 - datum.RA_ICRS" "fakeLongitude"-                       -  in toVegaLite [ projection [ PrType Mercator ]-                , gaiaData-                , trans []-                , mark Circle []-                , enc []-                ]---- $intro-layered--- The Stacked-Histogram plot - created by 'gmagHistogramWithColor' - showed--- the distribution of the \"Gmag\" field by cluster, but it was hard to--- compare them. A common approach in this situation is to split up--- the data into multiple plots ---- the <https://en.wikipedia.org/wiki/Small_multiple small multiple>--- approach (also known as trellis plots) - which we can easily achieve in--- Vega Lite. It also gets us back on track with the Elm walkthrough.--{-|--Our first attempt is with the 'column' function, which tells-Vega-Lite to create a plot for each @Cluster@ field (and introduces-us to the @F@ family of 'FacetChannel' constructors).--The legend has been turned off with @'MLegend' []@, since it doesn't-add anything to this visulization (as the individual plots, labelled-by the cluster name, provide the same information).--<<images/vl/smallmultiples.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMmBINgR5SsgAcTgRRlVqaHQFHCg2OgAPVvbO+G7IOQB9XoG0SDaOroBfBbwF3CoAEg5FdLhGFnYuXjck8UlpITFlbi2d+2O-OgkLKwBmIQArDjUCqk0VfDEqhaaAolEgKjopXqRTEcjo+EYAGE6LJnKMiABPNhyVrKaCA2AMbBQeIiTQItBtOh0VaFKDTciQGFwilQJqwFrEyDoQFkIjwahyLmY7GMACO1Fg6gkxDENkgtMoUAh7VU0Nh8KRKKcXWFWJxMxS+NUhIVazBGMqdKoHJE8FsxANysM6h+SqgIqdkAlUqIMr98vNSsgsD6Yg49T9RHijAAckMFGBlEUwABlEjwCPLJXZsCK52qGHA8jLBZAA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PName \"Gmag\", PmType Quantitative, PBin [] ]-            . position Y yAxis-            . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]-            . 'column' [ 'FName' \"Cluster\", 'FmType' Nominal ]--    yAxis = [ PAggregate Count-            , PmType Quantitative-            , PAxis [ AxTitle \"Number of Stars\" ]-            ]-    -in toVegaLite-     [ gaiaData-     , mark Bar []-     , enc []-     ]-@--Since we have nine clusters in the sample, the overall visualization is-too wide, unless you have a very-large monitor. Can we do better?---}--smallMultiples :: VegaLite-smallMultiples =-  let enc = encoding-              . position X [ PName "Gmag", PmType Quantitative, PBin [] ]-              . position Y yAxis-              . color [ MName "Cluster", MmType Nominal, MLegend [] ]-              . column [ FName "Cluster", FmType Nominal ]--      yAxis = [ PAggregate Count-              , PmType Quantitative-              , PAxis [ AxTitle "Number of Stars" ]-              ]-      -  in toVegaLite-       [ gaiaData-       , mark Bar []-       , enc []-       ]---{-|--The number of columns used in small-multiple can be defined using the-'columns' function. However, this requires us to:-- * move the facet definition out from the encoding and into the top-level,-   with the 'facetFlow' function;-- * and define the plot as a separate specification, and apply it-   with 'specification' and 'asSpec'.--The actual syntactic changes to 'smallMultiples' are actually-fairly minor:--@-let enc = encoding-            . position X [ PName \"Gmag\", PmType Quantitative, PBin [] ]-            . position Y yAxis-            . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]--    yAxis = [ PAggregate Count-            , PmType Quantitative-            , PAxis [ AxTitle \"Number of Stars\" ]-            ]-    -in toVegaLite-     [ gaiaData-     , 'columns' 4-     , 'facetFlow' [ FName \"Cluster\", FmType Nominal ]-     , 'specification' ('asSpec' [ mark Bar [], enc [] ])-     ]-@--<<images/vl/smallmultiples2.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCEwJBksDgCBZAA4iYshJBiWLLcgqlQZHgAHrX1jc0pUPwA+m2dqHUNTTiQAL5T6VNpmBRk-EIF6ZgmOBq13CWp6-1iotBsYjWo6BiYong55Zls-HjQtQDCeHzmLZDwAJ7LXREslOsAIfUgwRYUheqHqeDw8wOmBGaCyj2etSqsBq4O4p0I8BwWH44L+ANGAEcsLAJBwEGx9NMFlcoL81iyMtiWDgDAh+LVRFgJPsOZgyfzKdTaYh4Az+cyOZBYO02BRyrL4MFagA5caCMAiTJgADKiFK0yRYFmV2tVuZkAAJBQhNETLUSOQqLQrGF2JweEw2CJqM7XUYfU48BxtLoAMxMABWFHEIqgNwaYjVqAALPbMrAhPx8hc0U8YVB3p9elBxYDgWJQUz0pBRGIHuc0LMpkA Open this visualization in the Vega Editor>--Note that Vega Lite does support a @\"facet\"@ field in its encodings,-but hvega follows Elm VegaLite and requires you to use this-<https://github.com/gicentre/elm-vegalite/issues/5#issuecomment-514501218 wrapped facet> approach.---}--smallMultiples2 :: VegaLite-smallMultiples2 =-  let enc = encoding-              . position X [ PName "Gmag", PmType Quantitative, PBin [] ]-              . position Y yAxis-              . color [ MName "Cluster", MmType Nominal, MLegend [] ]--      yAxis = [ PAggregate Count-              , PmType Quantitative-              , PAxis [ AxTitle "Number of Stars" ]-              ]-      -  in toVegaLite-       [ gaiaData-       , columns 4-       , facetFlow [ FName "Cluster", FmType Nominal ]-       , specification (asSpec [ mark Bar [], enc [] ])-       ]----- $intro-multiplot--- There are four ways in which multiple views may be combined:------ * The __facet operator__ takes subsets of a dataset (facets) and---   separately applies the same view specification to each of---   those facets (as seen with the 'column' function above).---   Available functions to create faceted views:---   'column', 'row', 'facet', 'facetFlow', and 'specification'.------ * The __layer operator__ creates different views of the data but---   each is layered (superposed) on the same same space; for example---   a trend line layered on top of a scatterplot.---   Available functions to create a layered view: 'layer' and 'asSpec'.------ * The __concatenation operator__ allows arbitrary views (potentially---   with different datasets) to be assembled in rows or columns.---   This allows \'dashboards\' to be built.---   Available functions to create concatenated views:---   'vConcat', 'hConcat', and 'asSpec'.------ * The __repeat operator__ is a concise way of combining multiple views---   with only small data-driven differences in each view.---   Available functions for repeated views: 'repeat' and 'specification'.---{-|--We start with a \"basic\" plot for the dataset: the median value-of the parallax of the stars in each cluster.--<<images/vl/baseplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMmBINgR5SsgAcTgRRlVqaHQFHCg2OgAPVvbO+G7IOQB9XoG0SDaOroBfBbwF3CoAEg5FdLhGFnYuXjck8UlpITFlbi2d+2O-OgkLKwBmIQArDjUCqk0VfDEqhaaAolEg03IkCKYjkdHwjAAwnRZM5RkQAJ5sOStZTQQGwBirQpQdH1aGw+EzKajWAiETwWzEbEzaByAGwVRozHMqAAR2oHKIEmIYhskGWECJVBUqmhwPIywWQA Open this visualization in the Vega Editor>--@-let plx = position Y [ PName \"plx\", PmType Quantitative, PAggregate 'Median' ]-    cluster = position X [ PName \"Cluster\", PmType Nominal ]-    enc = encoding . cluster . plx-             -in toVegaLite-      [ gaiaData-      , mark Bar []-      , enc []-      ]-@--}--basePlot :: VegaLite-basePlot =-  let plx = position Y [ PName "plx", PmType Quantitative, PAggregate Median ]-      cluster = position X [ PName "Cluster", PmType Nominal ]-      enc = encoding . cluster . plx-               -  in toVegaLite-        [ gaiaData-        , mark Bar []-        , enc []-        ]---{-|--We start our exploration by combining two visualizations, layering-one on top of the other. The base plot shows the same data as-'basePlot', and then on top we will show a horizontal line that-indicates the median parallax for all the stars in the sample.--<<images/vl/layeredplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCEwJBksDgCBZAA4iYshJBiWLLcgqlQZHgAHrX1jc0pUPwA+m2dqHUNTTiQAL5T6VNpmAAkFELRJrUk5FS0VmHsnDxMbCLUK2tGu054HNq6AMxMAFYU4qnpkHiwAJ7NqADa6QghRMOA0tW4JRakCkomgbDENVQhRGaCybH4eGgtQAwng+OYofAvmR+F0RLJ4bACDN5oDUSCwaMcFhgtN0gBdBb9MSw+GItB0yBfcqZdGY2rDKGwFgsHAGBCk0ayfhw2BiQnExVQACOWDV8A4CDY+jZEFpmFEYlF-OAsymQA Open this visualization in the Vega Editor>--@-let plx = position Y [ PName \"plx\", PmType Quantitative, PAggregate Median ]-    cluster = position X [ PName \"Cluster\", PmType Nominal ]-             -    perCluster = [ mark Bar [], encoding (cluster []) ]-    allClusters = [ mark 'Rule' [] ]-    -in toVegaLite-      [ gaiaData-      , encoding (plx [])-      , 'layer' (map 'asSpec' [perCluster, allClusters])-      ]-@--For this visualization, the specification starts with the data-source and an encoding, but __only__ for the y axis (which means-that all layered plots use the same encoding for the axis). The-'layer' function introduces the different visualizations that-will be combined, each as there own \"specification\" (hence-the need to apply 'asSpec' to both @perCluster@ and @allClusters@).-Note that there is no x-axis encoding for the 'Rule', since the-data applies to all clusters (i.e. it should span the-whole visualization).---}-layeredPlot :: VegaLite-layeredPlot =-  let plx = position Y [ PName "plx", PmType Quantitative, PAggregate Median ]-      cluster = position X [ PName "Cluster", PmType Nominal ]-               -      perCluster = [ mark Bar [], encoding (cluster []) ]-      allClusters = [ mark Rule [] ]-      -  in toVegaLite-        [ gaiaData-        , encoding (plx [])-        , layer (map asSpec [perCluster, allClusters])-        ]-        --{-|--This example is similar to 'layeredPlot' but includes an x-axis-encoding for the second layer. We use this to show the range of the-data - so the minimum to maximum parallax range of each cluster - with-the 'Rule' type. The difference to the previous plot is that an-extra positional encoding is added ('Y2') to define the end point-of each line ('Y' is used as the start point).--<<images/vl/layereddiversion.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFACYCGKpGYoEEkArgE4A2VMKKADgM7oD0fRqQDuAOkTwU0egCN63WIwDGAewB2KWBtGqAtnwAiK+ogBCTANaw+0AG6xEpPrtLdNjG-cd8yFPo-hSAFpSYIA2AEYwkIicIIoZZlgI0lE1FSC4UmJFURRuW0hCWigAMxVGFzRMYEhOUkYFKlqAcRdENjV6XRlFIqhOZgAPTu7exn7IWAB9QZHMSC6evoBfFaIV4qhheGIpKlwCIkgAEm4lOBc2VC5eAS9UiSlZUXgVPnPLpweg5klrWxYUQAK246iKx2YpAAnn1MABtIgQGglKAuRgWZqQbjwABesCoACYCFAUNDOASFkp4MokpBNkjaFM1KpiPA1B0aoySpBoVjSvBYMxiGw5pNSIhEIwHORKWjYGzSGpJmSKWwAI70JUoSTkeD2encsDrEoMkoonnozELRj0OlbHlaVnsznUI10aGE-mC4Wi4biyXSxyaNguEZm1Ee71CkULMX4KASqUykMLXTslXkuWQTXa3U6g0m1FFiBFgC6W2Zzo5WPm1EgApjbAAwsx5O5M2qFul02pSKw1pXVGoBa7gOsVkA Open this visualization in the Vega Editor>--@-let plx op = position Y [ PName \"plx\", PmType Quantitative, PAggregate op ]-    cluster = position X [ PName \"Cluster\", PmType Nominal ]-             -    median = [ mark Circle [ 'MSize' 20 ]-             , encoding (plx Median [])-             ]-    range = [ mark Rule [ ]-            , encoding-                . plx 'Min'-                . position 'Y2' [ PName "plx", PAggregate 'Max' ]-                $ []-            ]-      -in toVegaLite-      [ gaiaData-      , encoding (cluster [])-      , layer (map asSpec [ median, range ])-      , width 300-      , height 300-      ]-@--The 'MSize' option is used to change the size of the circles so that they-do not drown out the lines (the size value indicates the area of the mark,-and so for circles the radius is proportional to the square root of this-size value; in practical terms I adjusted the value until I got something-that looked sensible).--Note that the y axis is automatically labelled with the different-operation types that were applied - median, minimum, and maximum --although there is no indication of what marks map to these operations.---}-layeredDiversion :: VegaLite-layeredDiversion = -  let plx op = position Y [ PName "plx", PmType Quantitative, PAggregate op ]-      cluster = position X [ PName "Cluster", PmType Nominal ]-               -      median = [ mark Circle [ MSize 20 ], encoding ( plx Median []) ]-      range = [ mark Rule [ ], encoding . plx Min . position Y2 [ PName "plx", PAggregate Max ] $ [] ]-      -  in toVegaLite-        [ gaiaData-        , encoding (cluster [])-        , layer (map asSpec [ median, range ])-        , width 300-        , height 300-        ]---{-|--Instead of layering one view on top of another (superposition), we can-place them side by side in a row or column (juxtaposition). In-Vega-Lite this is referred to as /concatenation/:--<<images/vl/concatenatedplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCEwJBksDgCBZAA4iYshJBiWLLcgqlQZHgAHrX1jc0pUPwA+m2dqHUNTTiQAL5T6VNpmLqiYkIIhADa6RDoGJgmOBq13CWpWxlSotBsYjWoO7uYI2hZbPx40LUAwnh85i2Q8AAnmR+F0RLJrrACPMzrtIIDyplXu9asN-rAWCwcAYEKDRrJ+FdYGJ-kCQbUAI5YYnwDgINj6aawsCzXYw3b3DL7Q6jY6TBYPSAXERXG4FZmPRHIj6jb6-XpQMl4qARCFiKHTAUPKAIu4vN4yqBVDHozHYwySWoEokkvoA4HKyBUml02mM1kPD0QD0AXQFkAAJBQhNETLUSOQqLQrGF2JweEw2CJqMHQ0YY048BxtLoAMxMABWFHEp0wyyRtzQsymQA Open this visualization in the Vega Editor>--@-let enc field = encoding-                 . position X [ PName \"Cluster\", PmType Nominal ]-                 . position Y [ PName field, PmType Quantitative, PAggregate Median ]-               -    parallaxes = [ mark Bar [], enc \"plx\" [] ]-    magnitudes = [ mark Bar [], enc \"Gmag\" [] ]-    -    specs = map asSpec [ parallaxes, magnitudes ]-    -in toVegaLite-      [ gaiaData-      , 'vConcat' specs-      ]-@--The 'hConcat' function would align the two plots horizontally,-rather than vertically (and is used in 'combinedPlot').--Note that as the axes are identical apart from the field for the y axis,-the encoding has been moved into a function to enforce this constraint-(this ensures the x axis is the same, which makes it easier to visually-compare the two plots). However, there is no requirement that the-two plots be "compatible" (they could use different data sources).---}---concatenatedPlot :: VegaLite-concatenatedPlot = -  let enc field = encoding-                   . position X [ PName "Cluster", PmType Nominal ]-                   . position Y [ PName field, PmType Quantitative, PAggregate Median ]-               -      parallaxes = [ mark Bar [], enc "plx" [] ]-      magnitudes = [ mark Bar [], enc "Gmag" [] ]-      -      specs = map asSpec [ parallaxes, magnitudes ]-      -  in toVegaLite-        [ gaiaData-        , vConcat specs-        ]---{-|--The alignment of the plots can be adjusted with 'spacing', which we-use here to remove the vertical gap between the two plots (the-example is written so that we can see the only difference between-the two plot specifications is the addition of @'PAxis' []@ to the-parallax plot).--<<images/vl/concatenatedplot2.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCEwJBksDgCBZAA4iYshJBiWLLcgqlQZHgAHrX1jc0pUPwA+m2dqHUNTTiQAL5T6VNpmLqiYkIIhADa6RDoGJgmOBq13CWpWxlSotBsYjWoO7uYI2hZbPx40LUAwnh85i2Q8AAnmR+F0RLJrrACH1ILB2mwKIR6ng8PMzrtIIDyplXu9asN-rAWCwcAYEKDRrJ+FdYGJ-kCQbUAI5YWnwDgINj6abosCzXZo3b3DL7Q6jY6TBYPSAXERXG4FXmPbG4j6jb6-XpQBkUqARCFiKHTKUPKBYu4vN5qqBVImE4mkwySWpUml0mE65msiQc9nc-kPAMQAMAXSlkAAJBQhNETLUSOQqLQrGF2JweEw2CJqNHY0YU048BxtLoAMxMABWFHEp0wFGKQmutzAvnDyxxzeAsymQA Open this visualization in the Vega Editor>--@-let enc field flag = encoding-                       . position X ([ PName \"Cluster\", PmType Nominal ] ++-                                     if flag then [ PAxis [] ] else [])-                       . position Y [ PName field, PmType Quantitative, PAggregate Median ]-             -    parallaxes = [ mark Bar [], enc \"plx\" True [] ]-    magnitudes = [ mark Bar [], enc \"Gmag\" False [] ]-    -    specs = map asSpec [ parallaxes, magnitudes ]-    -in toVegaLite-      [ gaiaData-      , 'spacing' 0-      , vConcat specs-      ]-@--Even though we set 'spacing' to @0@ there is still a small gap between-the plots: this can be removed by using @'bounds' 'Flush'@, but we'll-leave using that until the grand finale.---}--concatenatedPlot2 :: VegaLite-concatenatedPlot2 = -  let enc field flag = encoding-                         . position X ([ PName "Cluster", PmType Nominal ] ++-                                       if flag then [ PAxis [] ] else [])-                         . position Y [ PName field, PmType Quantitative, PAggregate Median ]-               -      parallaxes = [ mark Bar [], enc "plx" True [] ]-      magnitudes = [ mark Bar [], enc "Gmag" False [] ]-      -      specs = map asSpec [ parallaxes, magnitudes ]-      -  in toVegaLite-        [ gaiaData-        , spacing 0-        , vConcat specs-        ]----- $intro-repeat--- Creating the same plot but with a different field is common-enough--- that Vega-Lite provides the 'repeat' operator.---{-|--The 'concatenatedPlot' example can be extended to view the-distribution of several fields - in this case Right Ascension,-Declination, parallax, and magnitude:--<<images/vl/repeatplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMwYHsDuGYA2pAEoCCA+gJIDCpAypADRQAiAojfU65PABsAHiygBxALZIA5pAC6AX2bgoAZ0QBjQqAgRIU6AGtCkAEZJoLFXoAmqJNuu7IAV2gCTACxQp4q9AD0AdBIeAB00gCWKJ4upi6qsNAaOAB2KLDpYSkSAWw4LtIAQm6GsAGeAG6w0kgBUqoZ0BXVtQF2KHW1kUgAtEh9AGwAjIP9wwAMvZ2mArDDSGGpOL2eyDZJYSiqlVa6zgBmONBSaJg6+87wFonakJIyJqkuEqZJovzCTy9vlnywlEEIkwkGer3eCicEEh+yUTkgmRSNkiqVk5yhUGBWEgB0isAENhMtAECSaHxQAE9EE8cBIUUgPHDLlAKY5mXpcfjCecYAhkGcoNB8JAmezIDJpHBahkTBJYMikKk9mLKdSQQBHFyKlDRVCRaqQDEw3TG0WQAAkqg0aykXh8fkCAVaiyiMTiYUiOACVptdWdvQE0XKlQAzGEAFaqNLKyApVK4tFYSEKIA Open this visualization in the Vega Editor>--@-let enc = encoding-           . position X [ PName \"Cluster\", PmType Nominal ]-           . position Y [ 'PRepeat' 'Row', PmType Quantitative, PAggregate Median ]-            -    spec = asSpec [ gaiaData-                  , mark Bar []-                  , enc [] ]-                        -    rows = [ \"RA_ICRS\", \"DE_ICRS\", \"plx\", \"Gmag\" ]-    -in toVegaLite-      [ 'repeat' [ 'RowFields' rows ]-      , 'specification' spec-      ]-@---This more compact specification replaces the data field name-(for example @'PName' \"plx\"@) with a reference to the repeating field-('PRepeat') either as a 'Row' or 'Column' depending on the desired-layout. We then compose the specifications by providing a set of-'RowFields' (or 'ColumnFields') containing a list of the fields to which-we wish to apply the specification (identified with the function-'specification' which should follow the repeat function provided to-toVegaLite).---}--repeatPlot :: VegaLite-repeatPlot =-  let enc = encoding-             . position X [ PName "Cluster", PmType Nominal ]-             . position Y [ PRepeat Row, PmType Quantitative, PAggregate Median ]-            -      spec = asSpec [ gaiaData-                    , mark Bar []-                    , enc [] ]-                          -      rows = [ "RA_ICRS", "DE_ICRS", "plx", "Gmag" ]-      -  in toVegaLite-        [ repeat [ RowFields rows ]-        , specification spec-        ]---{-|--We can combine repeated rows and columns to create a grid of-views, such as a scatterplot matrix, adding in color-encoding to separate out the clusters:--<<images/vl/splomplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMoIRgewHcMwBtSAJQEEB9ASQGFyBlSAGigBEBROxl9yPAA2ADzZQA4gFskAc0gBdVuByQAxniEBXKQDtiZKr2bjI3Y-yjCxA6XMUqAvstwBnRGuLZVM6AGsvSFcASwAvWGIAVgEUAE9EYkE8YN00ZxVcABNUJC8M1S1oIUSACxQUeFd0AHpq6CQCADpZYJQSrQAjLVdYaA1U2FTGjSlqjjwtWQAhQr9YapKAN1hZJGqZVxReheXV6uyUNdXgpABaJDOANgBGS-PrgAZTw46hWGukRt08U5LkTN6jRQrkWbHyuAAZnhoDI0JhvDhVPAkNAeoE7PJMJBdDoOr1TNZEjipHjoKZYNRCVjiaTII5wWB6Yj0ojIIMNJkUpisAz1JpoYEIcFYEJMol6NpNviYvEItS8FIUkhiizEVAxPDIEKRWLNXBEKhEhptHo6TKEliAI5aJCpVqoYLLM282KC4WiwL65BwqDQQhmqBxC1Qa22lD28NOpk4aOqyAAElcaj+MlK5UqNWqu0+LTanUawTw1STKbW2dOQla80WAGZGgArVx4fQuKD9IXc4D0xxAA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PRepeat 'Column', PmType Quantitative ]-            . position Y [ PRepeat Row, PmType Quantitative ]-            . color [ MName \"Cluster\", MmType Nominal ]-          -    spec = asSpec [ gaiaData-                  , mark Point [ MSize 5 ]-                  , enc [] ]-                        -    fields = [ \"RA_ICRS\", \"DE_ICRS\", \"plx\", \"Gmag\" ]-    -in toVegaLite-      [ repeat [ RowFields fields, 'ColumnFields' fields ]-      , specification spec-      ]  -@--To be honest, this is not the best dataset to use here, as-there is no direct correlation between location (the @RA_ICRS@-and @DE_ICRS@ fields) and the other columns, but it's the-dataset I chose, so we are stuck with it.--Once you have sub-plots as a specification, you can combine-them horizontally and vertically to make a dashboard style-visualization. Interested parties should check out the-<https://github.com/gicentre/elm-vegalite/tree/master/docs/walkthrough#building-a-dashboard-1240 Building a Dashboard> section of the-Elm Vega-Lite Walkthrough for more details.---}--splomPlot :: VegaLite-splomPlot =-  let enc = encoding-             . position X [ PRepeat Column, PmType Quantitative ]-             . position Y [ PRepeat Row, PmType Quantitative ]-             . color [ MName "Cluster", MmType Nominal ]-            -      spec = asSpec [ gaiaData-                    , mark Point [ MSize 5 ]-                    , enc [] ]-                          -      fields = [ "RA_ICRS", "DE_ICRS", "plx", "Gmag" ]-      -  in toVegaLite-        [ repeat [ RowFields fields, ColumnFields fields ]-        , specification spec-        ]  ----- $intro-interactivity--- Interaction is enabled by creating /selections/ that may be combined with--- the kinds of specifications already described. Selections involve three--- components:------  * __Events__ are those actions that trigger the interaction such as---    clicking at a location on screen or pressing a key.------  * __Points of interest__ are the elements of the visualization with---    which the interaction occurs, such as the set of points selected---    on a scatterplot.------  * __Predicates__ (i.e. Boolean functions) identify whether or not---    something is included in the selection. These need not be limited---    to only those parts of the visualization directly selected through---    interaction.--{-|--The next several plots show different types of selection --select a single point, a range of plots, or follow the mouse - and-all have the same basic structure. To avoid repetition, and mistakes,-I am going to introduce a helper function which creates the-plot structure but without the selection definition, and then-use that to build up the plots.--The helper function, 'selectionProperties', takes two arguments, which are -the selection name and the plot title. The selection name is used-to identify the selection, as a visualization can support multiple-selections, and the plot title has been added mainly to show some-minor customization (the use of 'TOrient' to move the title to the-bottom).--The definition of this helper function is:--@-selectionProps selName label =-  let posOpts field = [ PName field-                      , PmType Quantitative-                      , PScale [ 'SZero' False ]-                      ]--      enc = encoding-               . position X (posOpts \"Gmag\")-               . position Y (posOpts \"plx\")-               -               . color [ 'MSelectionCondition' ('SelectionName' selName)-                           [ MName \"Cluster\", MmType Nominal ]-                           [ 'MString' "grey" ]-                       ]-                -               . 'opacity' [ MSelectionCondition (SelectionName selName)-                            [ 'MNumber' 1.0 ]-                            [ MNumber 0.3 ]-                         ]--               . 'size' [ MSelectionCondition (SelectionName selName)-                            [ MNumber 40 ]-                            [ MNumber 5 ]-                         ]-                         -      trans = transform-                 . 'filter' ('FExpr' \"datum.DE_ICRS < -20\")-         -  in [ gaiaData-     , trans []-     , mark Point []-     , enc []-     , title label [ TOrient SBottom ]-     ]-@--The three non-selection-related features added here are that-'SZero' is used to tell Vega Lite that we do not need 0 displayed-on either axis, which leads to a \"tight\" bounding box around-the data, a 'filter' is used to select a subset of rows, namely-only those with a declination less than -20 (via 'FExpr'),-and the plot title is moved to the bottom with 'TOrient'.--The main change is that the selection is used in the encoding section,-identified by name, using 'SelectionName' and the supplied-argument. It is used as a filter for the encoding section, where-'MSelectionCondition' defines the properties to use-when the selection occurs (the first list of properties) -and when it does not (the second list). This is used for-three different encodings:-- - 'color', where the selected star is labelled by its-   cluster color, and all the other are grey;-- - 'opacity', so that the selected star is fully opaque-   whereas un-selected stars are partially transparent;-- - and 'size', so that the selected star is much bigger-   than the others.--When no selection has been made - such as when the visualization-is first created - then all points are encoded with the-\"selected\" case (so colorful, fully opaque, and large in this-case).---}--selectionProperties ::-  T.Text-  -- ^ The selection name-  -> T.Text-  -- ^ The title for the plot-  -> [PropertySpec]-selectionProperties selName label =-  let posOpts field = [ PName field-                      , PmType Quantitative-                      , PScale [ SZero False ]-                      ]--      enc = encoding-               . position X (posOpts "Gmag")-               . position Y (posOpts "plx")-               -               . color [ MSelectionCondition (SelectionName selName)-                           [ MName "Cluster", MmType Nominal ]-                           [ MString "grey" ]-                       ]-                -               . opacity [ MSelectionCondition (SelectionName selName)-                            [ MNumber 1.0 ]-                            [ MNumber 0.3 ]-                         ]--               . size [ MSelectionCondition (SelectionName selName)-                            [ MNumber 40 ]-                            [ MNumber 5 ]-                         ]-                         -      trans = transform-                 . filter (FExpr "datum.DE_ICRS < -20")-         -  in [ gaiaData-     , trans []-     , mark Point []-     , enc []-     , title label [ TOrient SBottom ]-     ]---{-|--The actual plot just requires the selection information to be-defined and then added to the plot properties:--<<images/vl/singleselection.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEDsDKQ4gV6DtoABPAxUfTIEzBUZKIEaGBhQX4YjUW5mT4iKg06BgeBgIwmMzPSCYUjJGVQSLoDzoHDCyzJBL0fl2dZQBLkTBWhwOSDFeDkZg8z7BWBUDmUx02xIWukUiXWx0kbXkNmfARu6pPMNO6lUWn0-RMllUNnA-1QTnc05GkyuyCJgGOk1J0gALw9YGILrddYArBqEogg2mJc7Xe66AAWOQa5OpkPXZmsoU5qDoAzwOJhX3dxt9-ByNiEtuBsJd+s9pt0brD+Up4MMz4Zyf-aeQD57sjy6NQI7wE7DuKuuvEWuwdB0VCurEQJ5lydaQAAjswSB0jYdKlEoN5LvekZPoYdxXJA4KfjsP5-vgAHkEBGr5mBkHQWETCkPB5ZgJWkDtmQJwSgCihAA Open this visualization in the Vega Editor>--@-let selLabel = "picked"-    sel = 'selection'-            . 'select' selLabel 'Single' []-       -in toVegaLite (sel [] : 'selectionProperties' selLabel "Select a point")-@--The 'selection' function is used to define the selection, via one or-more applications of the 'select' function. The form of 'select' is-that the selection is named, in this case we use @\"picked\"@, and the-type is given (a 'Single' click), and then options, which in our case-there aren't any, so an empty list is used.--Note that @hvega@ does not track the selection names, and will allow-you to use a name that you have not defined.---}--singleSelection :: VegaLite-singleSelection =-  let selLabel = "picked"--      sel = selection-              . select selLabel Single []-         -  in toVegaLite (sel [] : selectionProperties selLabel "Select a point")---{-|--The only change here is to add a property to the selection - that-is @'Nearest' True@ - which means that the nearest point to the-click will be highlighted.--<<images/vl/nearestselection.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEDsDKQ4gV6DtEHNYFRqnQ4MwqM8YABPAxUfTIEzBUZKIEaGBhaX4YjUW5mT4iKg06BgDnabnaowmMyCzCkZJqqCRdAedA4WWWZIJeiSuzrKAJciYV0OByQYrwcj8-TBLlCyk+92JZ10ilKt0+khm8hsz4CQPVJ7x33Uqi0+n6Jksqhs4ERqDQEViz5TLAmAOQLMAn327OkABeVbAxH9gc7AFZBQlENH80q-QGg-gACxyQU5vOx67M1ky0tQdAGeBxMJhsc9ydgORsQmDqNhUdd8e9ujdOea3MxhmfQsr-5ryAfS9kTUpqBHeAnHOcQBp2xAdrA6B0KgAaxEC5aVvoACOzBIHSNh0qUSjvruX5Jr+hh3FckDgiBOzgZB+DQeQsGChWopIShphhEwpCYU2YAtpAQ5kCcSoAooQA Open this visualization in the Vega Editor>--@-let selLabel = "picked"-    sel = selection-            . select selLabel Single [ 'Nearest' True ]-       -in toVegaLite (sel [] : selectionProperties selLabel "Select nearest point")-@--One consequence of this change is that once a point has been selected you-can not remove this (i.e. un-select the point). This is in contrast to-'singleSelection', where clicking on an area with no stars would remove the-previous selection. The 'Clear' property can be added to the list-to define a way to clear the selection.---}--nearestSelection :: VegaLite-nearestSelection =-  let selLabel = "picked"--      sel = selection-              . select selLabel Single [ Nearest True ]-         -  in toVegaLite (sel [] : selectionProperties selLabel "Select nearest point")---{-|--The selection can easily be changed to allow multiple stars-to be selected, using shift-click, by swapping from 'Single' to 'Multi'.--<<images/vl/multiselection.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEDtwqRkGBmWASTFoGB4GByPALi58MRoABPAxUfRYZiUUhKIEaGBhUaMqi3MyfESuUioLlxPFxHRgaDoMDUqi0sBGEzLK6QTCkZLqqCRdAedA4eWWZIJegmE5C9ZQBLkTB2QOWYrwcjMCWfYKwKgiykOSwJRC+ukUgMplMkB3kej6ATR6pPcMOSBm2n0-RMllsjnVbm8-lUFzAnNQUXi07ukxRyDlgEpz0V5CkABesbA9hzkEj0enAFYOxW0xma0L51GY3QACxyZ6VtvmzMMz511ksxtcnl8gVKQOjyzoAzwOJhJPZucL3f4ORsISq6pokG5ZjO26LnQ3RHlWZ61lq9bXpyzb3m2j4jqukAfBBZBtoWnxHPAJywXEUbTsQU6wOgdCoFGsRAl2YrTpAACOzBIHSNh0qUShYV+uH5gR1x3La4LkTsVE0fgdHkAxR7dix7GcWETCkLxw5gKOkBpmQ-ozgCihAA Open this visualization in the Vega Editor>--@-let selLabel = "this is just a label"-    sel = selection-            . select selLabel 'Multi' []-       -in toVegaLite (sel [] : selectionProperties selLabel "Shift click to select points")-@---}--multiSelection :: VegaLite-multiSelection =-  let selLabel = "this is just a label"--      sel = selection-              . select selLabel Multi []-         -  in toVegaLite (sel [] : selectionProperties selLabel "Shift click to select points")---{-|--We can take advantage of browser event by using 'On' to define which-event to use, such as mouse movement over points:--<<images/vl/eventselection.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEDsDKQ4gV6DtoABPAxUfRYZiUUhXSAUz5YLKxdClP5AjQwMKjdlUW5mT4AWUlVDA4U1RhMNS16DA1KotLA8DAutMQswpGSKqgkXQHnQOBllmSCXoJhO+HsDkgCXImDs639xXg5GYPM+wVgVA5lIclgSiC9dJFYD9SY2tvIbM+Akj1SeoaTkGNtPp+iZLKobOB2agnO5pxdJgjkFLYABSbd-uQpAAXtHM5Bw5GRwBWZ4BxJpqu+scRqN0AAschnFfTDM+NdZSj7lnQBngcTCCcX45X+DkbEJM5T84zxCvI+6m6oNO31eZ+-+DagD5RzIT98ygI54BOTc4gjEdiGHWB0DoVAI1iIEmy5EdIAAR2YJA6RsOlSiUADIAvYDczAww7iFcFYJ2BCkPwFDyDQmdmyw3D8LCJhSGIntu2BWdEDIH1MwBRQgA Open this visualization in the Vega Editor>--@-let selLabel = "picked"-    sel = selection-            . select selLabel Multi [ 'On' "mouseover" ]-       -in toVegaLite (sel [] : selectionProperties selLabel "Move the pointer to select a point")-@--The supported list of events is described in the-<https://vega.github.io/vega/docs/event-streams/#selector Vega Event-Stream Selectors> documentation.--The addition of @Nearest True@ to the list of properties-sent to 'select' would avoid the flickering, as the mouse moves-between the stars.---}-eventSelection :: VegaLite-eventSelection =-  let selLabel = "picked"--      sel = selection-              . select selLabel Multi [ On "mouseover" ]-         -  in toVegaLite (sel [] : selectionProperties selLabel "Move the pointer to select a point")---{-|--The final 'Selection' value is 'Interval',-which lets you drag a rectangle to select the interior points:--<<images/vl/intervalselection.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEDtEPAsCZgmBSMgwK5tPQdtAAJ4GKj6Ew1YrwFz-YEwMKjPlUW5mT4cBBs+BgWBUWlIYKjMDQdBgala6BgIyi5BXSCYUjJJVQSLoDzoHBAjSQZIJeisuzrKAJciYX0OByQcXkZjCz7BTX8ykh-2Jb10in4ewJja28i8z4CCPVJ5+kOQY20+mnZms9mc7mwXnAjMwQVRqBTFlMlxFsAAkNu4vIUgALxb6eL4cjdAArA3QwlEMny2mwxKJ-gACxyZ4lqg0lMMz5M9tsjlcnlKP190PoAzwOJhONprvLiMtuRsQkzyxzhepsDEcctt0W6lnuFZHtWp51uevYzpAHx-iQWY5lARzwCcwFxBKI6QMOsDoHQqASrEQJQAKQr6AAjswSB0jYdKlEosEPghZA7shhh3Fa4JYTsuH4fghHkMRW5kS2kBUTRYRMKQDE9t20pzmQJxpgCihAA Open this visualization in the Vega Editor>--@-let selLabel = "naming is hard"-    sel = selection-            . select selLabel 'Interval' [ ]-       -in toVegaLite (sel [] : selectionProperties selLabel "Drag a rectangle to select points")-@---}--intervalSelection :: VegaLite-intervalSelection =-  let selLabel = "naming is hard"--      sel = selection-              . select selLabel Interval [ ]-         -  in toVegaLite (sel [] : selectionProperties selLabel "Drag a rectangle to select points")---{-|--The default interval option is to select a rectangle, but it can be restricted --such as to select all items within a range along a given axis-using 'Encodings':--<<images/vl/intervalselectiony.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEHZ1lBEPAsCZgmBSMgwNUKOQwK5tPQdskEvR2cg6ARIABPSBqKDQGUGKj6Ew1YrwFwAiBAjQwMKjHbUW5mT4cBAc6DoHlUGnQMBGdXcyIyx3aLXkeD3Z6QTCkZJmqCRdAedA4PWWUXocWIE74ewOSAJciYRkOJOa8jMVWfYKwKhy4EZ5OJcV0ikJpklsh24WfATZ6pPatJ6lUWn006s9mc7m88j8wWwYXFjOK5W55nhkxayCtnUOSNt0gALyniZLWZzdAArGPLAlEOWuwnINupwAWOS+9udyvMntxvs8umDgVCpRM5eWdAGeBxGEcpVuOUAXnQchsISB5QEeJ4PsQ4H4N0t52h2FYMp8LJss+XKvnyH4jl+GY-lAHxgMQtbkPWUBHPAJy3nEWobpA66wOgdCoFqsRAhOKr6AAjswSB0jYdKlEoY6yjsVE0YYdxXJA4LMTsbEcfgXHkDxvpKvxnxCSJYRMKQEmLsupaIGQ8YUQCihAA Open this visualization in the Vega Editor>--@-let selLabel = "naming is still hard"-    sel = selection-            . select selLabel Interval [ 'Encodings' [ 'ChY' ] ]-       -in toVegaLite (sel [] : selectionProperties selLabel "Drag to select points by parallax")-@--We'll come back to further things to do with interval selections-when we get to interactive plots below (see 'bindScales').---}---intervalSelectionY :: VegaLite-intervalSelectionY =-  let selLabel = "naming is still hard"--      sel = selection-              . select selLabel Interval [ Encodings [ ChY ] ]-         -  in toVegaLite (sel [] : selectionProperties selLabel "Drag to select points by parallax")----- $intro-selection-transforms--- Simple selections as described above create sets of selected data marks--- based directly on what was interacted with by the user. Selection--- transformations allow us to /project/ that direct selection onto other--- parts of our dataset.--{-|--For example, we can adjust the visualization to select all stars in the-same cluster, which is useful in this case since the Blanco1 and-IC2391 clusters occupy the same space in the magnitude-parallax-plane.--This is invoked simply by adding the 'Fields' constructor to the select-parameters naming the fields onto which we wish to project our selection.-Additionally, we have set the default selection with 'Empty' so that if-nothing is selected, the selection is empty-(as we have previously seen, without this the default selection is the-entire encoded dataset).--<<images/vl/transformselection.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEHZ1tdSHE9Ph7A5LIg5rAqNU6HBmFRgZzIFQsAZoABPU6JKiUzlQaUGeWfZAmYKjBWishUcj0ZB0AiQATkGI1SDKJkAiBAjQwMJa9kwKi3MyfER6qi0sDwMBGEzQZ7U73QX1gOJm6pPKCYUjJd1QSLoDzoHB2yzJBL0DWM0UJciYPOKyDFeBm1VQYK8mUihyQBKIHN0inO3X6-Sm80xyAh2n0-QGFl6Z4wKUq2VYEzlpTWuu90gAL0rxDLFboAFZR43mwPnWuhXQACxyUd9lsMz5D1lKDP19AGeBxMIy-flw-4ORsQnbxK71tgKu76Vt0Z5ev2AGGMOt7zh8gEkPGHafEc8AnGecTliukDLrA6B0Kg5axECSrjpWkAAI7MEgdI2HSpRKPOr7we29CDncVy9hhTrwTheH4AR5BEaOypkZR1FhEwpD0TaYB3g2iRkCc7IAooQA Open this visualization in the Vega Editor>--@-let sel = selection-            . select "pick" Single [ 'Fields' [ \"Cluster\" ]-                                   , 'Empty'-                                   , Nearest True-                                   ]-       -in toVegaLite (sel [] : selectionProperties "pick" "Select a point, select a cluster")-@---}--transformSelection :: VegaLite-transformSelection =-  let sel = selection-              . select "pick" Single [ Fields [ "Cluster" ]-                                     , Empty-                                     , Nearest True-                                     ]-         -  in toVegaLite (sel [] : selectionProperties "pick" "Select a point, select a cluster")---- $intro-selection-binding--- Selection need not be limited to direct interaction with the--- visualization marks. We can also /bind/ the selection to other--- user-interface components.--{-|--The Elm Vega-Lite walkthrough uses a dataset which has a-column for which a range-slider makes sense. The dataset I'm-using is less rich, and so I am going to use a HTML select-widget - a drop-down list of values - instead. This lets-the user select all stars from a given cluster, and is-introduced with the 'Bind' and 'ISelect' constructors.--The 'InOptions' list is given the values of the Cluster column that-can be selected: I start with a value not in the list (@none@) just to-indicate that no values are selected, and then the list of clusters in-this sub-sample (remembering that 'selectionProperties' applies a-declination cut off). Eagle-eyed readers will note that the cluster-names in this list (the @clusters@ variable) end in spaces: this is-because the input data file has the cluster names stored in an-eight-character field, even though it is a tab-separated file.-This surprised me when I first tried this visualization, and-using the value \"Blanco1\" did not select anything! Isn't working-with data so much fun!--<<images/vl/widgetselection.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoAY3SIyAczrEARvE0BrPbHTNE9OpCNVSeqkvURIWeLDP2ADuikiNCQ7gxM8IYaHsyw5PYAFtDQfsi4APTpCADubHqk0AnMRszINNrBVMFs2ljpHNZ6AEKxZlTpCQBuVHrw6V7I1LAd3b3pjNB9vaTwUvCzAGwAjAtzS3JSk0bkVEvwbIjoUglU8PQ0bNDInaHRUBjYTIaQft5lzwDiXgb4kIisjloqigfnIAA97P8sIDQlAqDxQRDflCYYpFBpFGFIAASZCaE5eRLJVIZdKjfb5QrFNikdDpPEEvrkqTkArtToAZjYACtkDpbh4yjtNNBaYgohAPH5SOYqHZ8KBJZLIFQsH5oABPSE6VxhJUOILysCKpXKgTkUpDCWm-VBPzMEK-IVUEUCm3K9DqsXIOgEP462GQJrkJDaJZQYGQQQyDkATnDEag0YWchkHkjADkPgIZAAWACs4cgyjuSvRNsxpagmr8ridQT0Ozd+rIVHI9B9+D95stNGLd3LYErHlF0CbCpgVDBjqgAAUdvAymBnSKwPAwJoLYM+5HMKQqjOHOhkugcMO4YhtPQG9aPNpyJhb8rOvALXWoJYqFq9cqKtfRfyCpVh4rbtvYPbbkCwFQCuAHir80qynYP76jW77+lgQSvpAVaDhA56CqQABe77EC+b50PmkZ-gUYrPORzDvrmciRrBdEITKbR2GiP6QJ6pgFFqE4Me+chsBy1E6P+7HGpAIl0EsrFti6cH+JxcpKARUBIrJoFGpAXzwAYrGaK+pGQCRVh0Kgr5lJi1YarW9gAI7MEgo5MKQ3RuHckBCbp+5gQh4KBniZnPJZ6DWbZVD2TAjnoa57kFJ53mDuiihAA Open this visualization in the Vega Editor>--@-let picked = "picked"--    clusters = [ \"none\", \"Blanco1 \", \"IC2391  \", \"IC2602  \", \"NGC2451 \" ]-    sel = selection-            . select picked Single [ Fields [ \"Cluster\" ]-                                   , 'Bind' [ 'ISelect' \"Cluster\" [ 'InOptions' clusters ] ]-                                   , Empty-                                   ]--   conf = configure-            . configuration (Background "beige")-               -in toVegaLite (conf [] :-               sel [] :-               selectionProperties picked \"Please select a cluster\")-@--Note that the selection works both ways: the HTML widget can be used-to select a cluster, and clicking on a point on the visualization will-update the HTML widget.--Unlike the other plots shown in the tutorial, this is a screen grab-rather than a PNG file created by Vega Embed. The background color was-changed - following the approach used in-'stripPlotWithBackground' - to show where the visualization "ends" and-the HTML select element starts. It also shows the Vega Embed "drop-down"-menu in the top-right corner, namely the three dots in a circle.---}--widgetSelection :: VegaLite-widgetSelection =-  let picked = "picked"--      clusters = [ "none", "Blanco1 ", "IC2391  ", "IC2602  ", "NGC2451 " ]-      sel = selection-              . select picked Single [ Fields [ "Cluster" ]-                                     , Bind [ ISelect "Cluster" [ InOptions clusters ] ]-                                     , Empty-                                     ]--      conf = configure-               . configuration (Background "beige")-               -  in toVegaLite (conf [] :-                 sel [] :-                 selectionProperties picked "Please select a cluster")----{-|--The selection can also be bound to an axis (or both axes, as in this-case), using 'BindScales' (applying it to the 'intervalSelectionY' plot).--<<images/vl/bindscales.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjtDbVidgHEtYP1EVkiacygDcgAPU-PL1SgqHhv7-EgzrAvaRUUNIoLFAACTIOKzLRuDxeXw+eoTULhKJsUjoHzgyEVBFSchhQrFADMbAAVshEmtLLFRnFoGjEHZ1tdSHECvQdpETOzPuD4KNkFdIMkEvQTMEBfgCJAAJ6C+5qKDQaUGKj6Ew1Yp8pSA4EwMKjHbUW5mT4cBDBMCYMAAL3Q6CwYHCVDA8FuVAFz0gmFIyRNUEi6A89qUuuF6FFiBO+HsDkgCXImEZDljmvIzFVn2CsCosuBybjiVFdIp0aZ+bIVHI3KgAjT1SeZdj1KotPp+gMLLZlOTsaVKtO9pMWsbAOTQKZkGQpGtGbAxFT6boAFZPQlEEW29HIAvZwAWOSe5utkvM1lUdn-PNQdAGeBxMKyrc7uhyNiE1eFsKbufbvmL-DdIelYtsWDKfB2Z4XuO+YfD+FZVvoRzwCch5xHys7EDOsDoHQqB8rEQKKsqs6QAAjswSB0jYdKlCGE6PnBPoIeBdyCryBpblhOH4Hh5AEZ6fYkeRlFhEwpC0aOYDQVAa5kFGc4AooQA Open this visualization in the Vega Editor>--@-let picked = "picked"--    sel = selection-            . select picked Interval [ Encodings [ 'ChX', ChY ], 'BindScales' ]-       -in toVegaLite (sel [] : selectionProperties picked "Drag or zoom the axes")-@--The image here was created after panning and zooming into the data.---}--bindScales :: VegaLite-bindScales =-  let picked = "picked"--      sel = selection-              . select picked Interval [ Encodings [ ChY, ChX ], BindScales ]-         -  in toVegaLite (sel [] : selectionProperties picked "Drag or zoom the axes")----- $intro-coordinated-views--- One of the more powerful aspects of selection-based interaction is in--- coordinating different views – a selection of a data subset is projected--- onto all other views of the same data.--{-|--The following plot doesn't contain anything new, but allows us to-select a rectangular-range on one plot, and see the same selection-automatically applied to the other plots. This is achieved by-combining the 'repeat' fuction with the 'selection'; this causes the-selection to be projected across all views as it is duplicated.--For this example we use all the clusters, rather than the subset of-Southern ones. One trick I use is to convert the Right Ascension-values (which have a domain of 0 to 360 degrees, and wrap around at-the 0\/360 mark), into their cosine values (remembering to convert to-radians first), and display that instead. This ensures the \"Blanco1\"-cluster members are spatially co-located on this axis - with values-close to 1 - rather than appearing near 0 and 360.--<<images/vl/coordinatedviews.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMwYHsDuGYA2pAMY4DOASgIKQA0UAIgKID6AkgMJUDKkAXUZkcAGwCuAWwB2hEvFEAPBlADikpAHNBAX3rgoFRKUKgIESCmhJpFAGY5okuQfNZISCoRHU6w0kiipOKiqLDe5BQAFAAmqFIAdLScPLxgAFRgAAocYAD0YACMABwADACUkDquYEI1kBrQANYRAJbQpKLh+m6QcShIpjUW4tCi3gAWKCjwFOh5edZ4CZqtKBPiAEbiFLAdONIosIcJ5JJ5TDjimgBCo02weRMAbrCaSHkaFEfQT6-veX6H3erSQAFokOCAGyFKEQwqlMEDTZdQpIBLSHBgibIGJ7BIoCjPBjDKAOJyoIZuXrwJDQXamSDqLTeaRSTZ7FSQBTKTCQNmSDnQLmwNg81nsznValgaXmPT1XZdUgoVoHRnwVqkB4xRkoACeiG8rUOe2egSqCt6x3IMRN2kwZmpIlEjipMqg5ok4T5mjg+pJHqg5GkdtV6sdpN6dlasFEur5XAk305PSDhjjsBVatkfM12tgurTQcshp9UExkhNFqjstJVudvPcMbjCfccEQlL55AkMiqwgNRr5AEdxDZVQNVa9+6TIAHHZAW-HGR3kGg+dB8P2oIPy5BR+O1qhWtO5RA5Q3IAASCikHEaSbTWbzPL-dGrdZbBJqvK3+8fN8wVENZHmeABmBIACsKHVNMRGkGMHSwaodCAA Open this visualization in the Vega Editor>--@-let enc = encoding-            . position X [ PRepeat Column, PmType Quantitative ]-            . position Y [ PRepeat Row, PmType Quantitative ]-            . color-                [ MSelectionCondition (SelectionName \"picked\")-                  [ MName \"Cluster\", MmType Nominal ]-                  [ MString \"grey\" ]-                ]--    sel = selection-            . select \"picked\" Interval [ ]--    trans = transform-            . calculateAs "cos(datum.RA_ICRS * PI / 180)" "cosRA"--    spec = asSpec-             [ gaiaData-             , trans []-             , mark Circle []-             , enc []-             , sel []-             ]--in toVegaLite-     [ repeat-       [ RowFields [ \"cosRA\", \"DE_ICRS\" ]-       , ColumnFields [ \"plx\", \"Gmag\" ]-       ]-     , specification spec-     ]-@---}--coordinatedViews :: VegaLite-coordinatedViews =-  let enc = encoding-              . position X [ PRepeat Column, PmType Quantitative ]-              . position Y [ PRepeat Row, PmType Quantitative ]-              . color-                  [ MSelectionCondition (SelectionName "picked")-                    [ MName "Cluster", MmType Nominal ]-                    [ MString "grey" ]-                  ]--      sel = selection-              . select "picked" Interval [ ]--      trans = transform-                . calculateAs "cos(datum.RA_ICRS * PI / 180)" "cosRA"--      spec = asSpec-               [ gaiaData-               , trans []-               , mark Circle []-               , enc []-               , sel []-               ]-               -  in toVegaLite-       [ repeat-         [ RowFields [ "cosRA", "DE_ICRS" ]-         , ColumnFields [ "plx", "Gmag" ]-         ]-       , specification spec-       ]---{-|--If the interval selection is bound the the axes with 'BindScales'-then we can zoom and pan the related plots - i.e. changing the-range displayed in one plot will also change the two plots that-it shares an axis with in this two by two arrangement. The conditional-encoding of the 'color' channel has also been removed.--<<images/vl/coordinatedviews2.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMwYHsDuGYA2pAEoCCA+gJIDCpAypADRQAiAojfUwLquQAxjgA2AVwC2AO0Il4IgB4soAcQlIA5pF4BfZuCgBnRIMKgIESOugBrQkICW0QSNgsDlgCaokZjxcgxaBF7AAsUFHhDdAB6GOgkPAA6DQcUULEAIzFDWGccKRRYQqThCRi2HDENACEgm1gY0IA3WA0kGPVDIugm1vaY7xQO9ockAFokCYA2AEZpydmABnHhzNdZpCSpHHHQ5E88pJRDZvcLAIAzHGh1NExzC4D4JGhcs0g1TXspSUy85SQeRKTCQX4Sf7QQGwSjAn5-AE6fwQJEXPT+SC5VyCFAOAofeAOQQNTwfTIOKSk0GGQRIVyGQEoACeiHsFJ6zTpkB06IukGKwk8FK0D2RUGEIhuH0uDlgIipUFo4m6AIEzNZoJ2EgpXN5T0gIKwkBlcoV2DgiFQ9glkhkeig6rcoIAjmIkIU0qgHK1ufonlAmdLZfKPhbkPcoNB8L6HSynVBXe7ccNcT7URZ03rIAASGn7dRhCJRWIxfpbVLpLJJPExPOwdSltoTERpRrNADMSQAVoZ8X7xQUZSKsEidEA Open this visualization in the Vega Editor>--The image was captured after panning and zooming in the-\"parallax-RA_ICRS\" plot.--@-let enc = encoding-            . position X [ PRepeat Column, PmType Quantitative ]-            . position Y [ PRepeat Row, PmType Quantitative ]-            . color [ MName \"Cluster\", MmType Nominal ]--    sel = selection-            . select \"picked\" Interval [ BindScales ]--    spec = asSpec-             [ gaiaData-             , mark Circle []-             , enc []-             , sel []-             ]--in toVegaLite-     [ repeat-       [ RowFields [ \"RA_ICRS\", \"DE_ICRS\" ]-       , ColumnFields [ \"plx\", \"Gmag\" ]-       ]-     , specification spec-     ]-@--The \"cosine\" transformation has been removed in comparison to-'coordinatedViews'.---}--coordinatedViews2 :: VegaLite-coordinatedViews2 =-  let enc = encoding-              . position X [ PRepeat Column, PmType Quantitative ]-              . position Y [ PRepeat Row, PmType Quantitative ]-              . color [ MName "Cluster", MmType Nominal ]--      sel = selection-              . select "picked" Interval [ BindScales ]--      spec = asSpec-               [ gaiaData-               , mark Circle []-               , enc []-               , sel []-               ]-               -  in toVegaLite-       [ repeat-         [ RowFields [ "RA_ICRS", "DE_ICRS" ]-         , ColumnFields [ "plx", "Gmag" ]-         ]-       , specification spec-       ]-  --{-|--The ability to determine the scale of a chart based on a selection is-useful in implementing a common visualization design pattern, that of-'context and focus' (or sometimes referred to as 'overview and detail-on demand'). We can achieve this by setting the scale of one view-based on the selection in another. The detail view is updated whenever-the selected region is changed through interaction:--<<images/vl/contextandfocus.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCEwJBksDgCBZAA4iYshJBiWLLcgqlQZHgAHrX1jc0pUPwA+m2dqHUNTTiQAL5T6VNpmLqiYkIIhADa6RDoGJjRbCwkhAAcvgu7UCY4GrVkImwSqVsZDGzQnIQALL5nz5gCwSE8DY4nK3BwfCI5SkomgDxYFA2kAAnpAALp9SDwZFkfi1B7mXSwAgzc67LEcYK1ADK-EB8DAsDAAE0wPQxCx+GB4CIwAAvEQiWRgB5gJp4EQMJ4XforERwjkFP4ZEZoZXkzJsOnQWpVWA1MkyqAUVZU1CFPmCESETLEgTzdUZbG42oARywsAkHAQbH0kEdDqNUFR5qyWrwOtGwxaWJxeNG7s9wMQwL9sxl6YwgYwO3JVxuUfuj0NmFe7yhqG+vxlkBh8vhSqDkFEEsmoc12tqAGE8HxzDHnfGoBFZA9idMSyrG0GoB2I7rqtKZ5ATcShxarTa7fxs03B26PV6U768ZPybB2mxEaHk2awPU8HhMxmz8Hp0255HWh0l03V3fCmgIVYAecoAX4IEQTEWpwUhaZdyNWMXQTQ9kx9P0A2VZ8wEzDF0kgAASE1ohMWoSHIKhaCsMJ2E4HgmBBahiP4ExqGopw8A4bRdAAZiYAArChQXOZtxE1GpzVmKYgA Open this visualization in the Vega Editor>--@-let sel = selection . select \"brush\" Interval [ Encodings [ ChY ] ]--    encContext = encoding-                   . position X [ PName \"Gmag\", PmType Quantitative, PScale [ SZero False ] ]-                   . position Y [ PName \"plx\", PmType Quantitative ]--    specContext = asSpec [ width 400-                         , height 80-                         , sel []-                         , mark Point []-                         , encContext []-                         , title \"Select a Y range to zoom in below\" []-                         ]--    encDetail = encoding-                  . position X [ PName \"Gmag\"-                               , PmType Quantitative-                               , PScale [ SZero False ]-                               , PAxis [ 'AxNoTitle' ]-                               ]-                  . position Y [ PName \"plx\"-                               , PmType Quantitative-                               , PScale [ SDomain ('DSelection' \"brush\") ]-                               ]-                  . color [ MName \"Cluster\", MmType Nominal ]--  specDetail =-      asSpec [ width 400, mark Point [], encDetail [] ]--in toVegaLite-     [ gaiaData-     , vConcat [ specContext, specDetail ]-     ]-@--Not shown here, but selecting a range of y-values in the top plot-(@specContext@) will cause the second plot (@specDetail@) to zoom-in on that range, as the selection is bound to the y axis of this-plot via 'DSelection'.---}--contextAndFocus :: VegaLite-contextAndFocus =-  let-    sel =-        selection . select "brush" Interval [ Encodings [ ChY ] ]--    encContext =-        encoding-            . position X [ PName "Gmag", PmType Quantitative, PScale [ SZero False ] ]-            . position Y [ PName "plx", PmType Quantitative ]--    specContext =-        asSpec [ width 400, height 80, sel [], mark Point [], encContext []-               , title "Select a Y range to zoom in below" []-               ]--    encDetail =-        encoding-            . position X-                [ PName "Gmag"-                , PmType Quantitative-                , PScale [ SZero False ]-                , PAxis [ AxNoTitle ]-                ]-            . position Y [ PName "plx"-                         , PmType Quantitative-                         , PScale [ SDomain (DSelection "brush") ]-                         ]-                  . color [ MName "Cluster", MmType Nominal ]--    specDetail =-        asSpec [ width 400, mark Point [], encDetail [] ]-        -  in-    toVegaLite-      [ gaiaData-      , vConcat [ specContext, specDetail ]-      ]----- $intro-crossfilter--- The final example in this section brings together ideas of view--- composition and interactive selection with data filtering by implementing--- /cross-filtering/: the selection of a subset of the data in one--- view then only displaying that data in the other views.--{-|--Here we show distributions of the four main numeric quantities-in the dataset - position, magnitude, and prallax - using the-@totalEnc@ encoding, and add a second layer which repeats this-data but with a different color (@selectedEnc@), and that is tied to-the interval-selection along the x axis ('ChX').--<<images/vl/crossfilter.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMxIGMD2ANgK4C2AdhmANqQBKAggPoCSAwrQMqQA0UAIgFEW7Lr0gBxEkgDmPKPAIAPSAF0Avt3BQAzohyVQECJAAmqJAa1GoRaAUqQAFihTxt6APQfoSAO4A6aQBLFEciACMibVhofDIUWHj-fBIPPjwiaQAhWwBrWA9HADdYaSQPKW0E6EKSso8zFHKyoKQAWiR2gDYARi6OnoAGNqbwglgepH8yPDbHZBMY-xRtIp4rI0gAMzxoKTRMQ2tN+CRoaIMJKVlMSDJScJi5SAVlW-uSR+hn2EZXhw+X0gag2EBB1g0G0gBCQAE8npgqKCsMjjFJoLkHOEzutjptEvgTEEyDcUXjrJA3lhtkFYAQTJc4IhUA58MRyMCxChYYgHABHIhIeIhVBBEqc1GbWGXGTSOBlBKsjLxZ7c3m3AVClAi7Xi8Hk-UQzR4o54yAoHxkbQ7PaUKjYLZBAjVS7RcY4bV4Ci3cLQKKOYFqFTG8mQdGYn04kNmt2wD1BL2XX3+y4EvBEknaO2U1RcnmwBzE6pFJD2NSQ8lQNMZ0mm0Ns3aXEvEAu3aSERZkaDpiWV4xUh20+mMhDIA5QNmkCgaKBq1tQTXCpq6gsVvuQaWHSCy+Woee4ZVoPPqheCpeivWSw1Ga8qLRryAAEm0OHmUgczlc7i8dSmwVCET+AmHgvm+5S-m0BAhAURQAMz+AAVtoiYhgeZCOrWIJqEAA Open this visualization in the Vega Editor>--Selecting a small range of parallax values in the fourth plot-highlights the associated data in the other three plots.--@-let sel = selection . select "brush" Interval [ Encodings [ ChX ] ]--    filterTrans = transform . filter ('FSelection' "brush")--    -- borrow a function from Elm-    pQuant = PmType Quantitative-    -    totalEnc = encoding-                . position X [ PRepeat Column, pQuant ]-                . position Y [ PAggregate Count, pQuant ]--    selectedEnc = totalEnc-                    . color [ MString "goldenrod" ]-            -in toVegaLite-     [ repeat [ ColumnFields [ \"RA_ICRS\", \"DE_ICRS\", \"Gmag\", \"plx\" ] ]-     , specification $-         asSpec-           [ gaiaData-           , layer-             [ asSpec [ mark Bar [], totalEnc [] ]-             , asSpec [ sel [], filterTrans [], mark Bar [], selectedEnc [] ]-             ]-           ]-     ]-@---}--crossFilter :: VegaLite-crossFilter =- let-    sel =-        selection . select "brush" Interval [ Encodings [ ChX ] ]--    filterTrans =-        transform-            . filter (FSelection "brush")--    -- borrow a function from Elm-    pQuant = PmType Quantitative-    -    totalEnc =-        encoding-            . position X [ PRepeat Column, pQuant ]-            . position Y [ PAggregate Count, pQuant ]--    selectedEnc =-        totalEnc-            . color [ MString "goldenrod" ]-            - in- toVegaLite-    [ repeat [ ColumnFields [ "RA_ICRS", "DE_ICRS", "Gmag", "plx" ] ]-    , specification $-        asSpec-            [ gaiaData-            , layer-                [ asSpec [ mark Bar [], totalEnc [] ]-                , asSpec [ sel [], filterTrans [], mark Bar [], selectedEnc [] ]-                ]-            ]-    ]  ---- $intro-error--- Here we dive into some of the ways for representing the spread--- of a value, focussing on the \"error\" of a variable.--{-|-We have already seen "error bars" in the 'layeredDiversion' plot, where-the 'Rule' type was used to draw a line between the 'Y' and 'Y2'-encodings. In that example the two positions were calculated \"on the-fly\" by Vega-Lite (using the 'Min' and 'Max' aggregation operations).-In this example I use the data to calculate the display range,-namely @plx - e_plx@ to @plx + e_plx@. These are mapped to the-'X' and 'X2' channels (not because it makes a better visualization,-but just to show you can create lines along the x axis), and a-small-multiples approach is used to separate out the clusters, but-only after a filter designed to select the two clusters - with the-\"most interesting\" data for this plot - has been applied.--<<images/vl/errormanual.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxhJUBLAG2gFNY8oATeaAVywDoBhKt5OrAIAGALpgAvBLABybjLAAfRWBbsuvfoJHipsgBIzIAXwA0xCGXjJGkAA5UAHgH0q6SKagBjeFS9sqVlpbNQ5OB0cwAFpVVjDaZwiTcxJSSGtbCOcACwoPb19-QLoQuK4IsABqWPVOBKTjYlEUqCx4WABrW1gA4JbINXhGUFTINlgqW2zoaDtkXAB6BYQAd04AcwpobLYAI356L3REOhPOI6wFgBF0NnWAIXGO2gXsgDdadfgFtoF6V4+XwWgwWXwo8Ci8AhADYAIzQyGw4RRaDwXZUWiw+CcRDoKLZWjwJj0TjQZBvDwWKAYbCsYb2drIYL4MgAcTa61siA4u3o+XsTi5PL5nkg9UF+Eg3KwvIYxkaEDMxEgABJkF4CW0pjM5osFoDsZttntOBR0At1ZrvgaolQti83gBmTgAK2Qx0pEEgTIxXmgZsQ9LsFC8zyY9N2FEQ4cl6t8tBsougAE87MyoFHBG9fCYlV7aIgjkwo5yWVTII4AEz0yi0KgxqBZXLJcuOYZUr21+uZJyudwtUZxjH0gBe9Hc+FQviZedSUBTadsAEc2Eh-aj-R9PXP0o4KDYWTAtsPJXZ2r5ApEABS-ACUJips69Rz4WEDh67Dcgmj+DCTqfTKV0CwKMcyfKBkxrCg6y-dl4E5f9F0lFc1y2VgKC3BUwFnSAjkQShS1IRpjCAA Open this visualization in the Vega Editor>--@-let trans = transform-              . filter (FExpr \"datum.Cluster[0] == \'C\' || datum.Cluster[0] == \'H\'\")-              . calculateAs \"datum.plx - datum.e_plx\" \"plx_lo\"-              . calculateAs \"datum.plx + datum.e_plx\" \"plx_hi\"-  -    errorEnc = encoding-                 . position X [ PName \"plx_lo\"-                              , PmType Quantitative-                              , PScale [SZero False]-                              , PAxis [ AxTitle "parallax (mas)" ]-                              ]-                 . position 'X2' [ PName \"plx_hi\" ]-                 . position Y [ PName \"Gmag\", PmType Quantitative ]-                 . column [ FName \"Cluster\", FmType Nominal ]-    -    sel = selection-            . select "picked" Interval [ BindScales ]--in toVegaLite [ gaiaData-              , trans []-              , errorEnc []-              , mark Rule []-              , sel []-              ]-@--For the interested reader, it was the calculation of the @\"plx_hi\"@-column that lead me to the discovery that the columns were being-read in as a string, and the introduction of the 'Parse' option-to 'gaiaData'.--As can be seen, the @e_plx@ terms are generally very small. This is-good for anyone using the data, as we want precise measurements, but -makes it harder for me to come up with meaningful visualizations! I-have taken advantage of the 'BindScales' interaction to zoom in on-a subset of stars which show larger parallax errors:--<<images/vl/errormanual-zoomed.png>>---}--errorManual :: VegaLite-errorManual =-  let trans = transform-                . filter (FExpr "datum.Cluster[0] == 'C' || datum.Cluster[0] == 'H'")-                . calculateAs "datum.plx - datum.e_plx" "plx_lo"-                . calculateAs "datum.plx + datum.e_plx" "plx_hi"-  -      errorEnc = encoding-                  . position X [ PName "plx_lo"-                               , PmType Quantitative-                               , PScale [SZero False]-                               , PAxis [ AxTitle "parallax (mas)" ]-                               ]-                  . position X2 [ PName "plx_hi" ]-                  . position Y [ PName "Gmag", PmType Quantitative ]-                  . column [ FName "Cluster", FmType Nominal ]--      sel = selection-              . select "picked" Interval [ BindScales ]--  in toVegaLite [ gaiaData-                , trans []-                , errorEnc []-                , mark Rule []-                , sel []-                ]--{-|--Alternatively, I could have made life simpler for myself and used-the 'ErrorBar' (or 'ErrorBand') mark type, together with 'XError'-(or 'YError') to indicate that the channel gives the offset from-the central value. For this visualization I restrict to a single-cluster (since I now know there's only one in this sample which-begins with @C@), but retain the 'column' encoding as a means-to getting a useful title. I've also switched things so that the-errors are back along the y axis.--<<images/vl/errorauto.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoBhc55a2AgAwBdMAF5RYAOQdJkAL5CANOChZ4sANZ1INWJgBG6yMoiRG0eHVARTzWOW0ALaNAAOyXAHpPCAO5sAc1JoR2Z9HhoAY3REali2aKxPABF0ZgCAITsNKk9HADcqAPhPNV4aPMLiz3MS4tJ4AFp4JoA2AEZW5vaBRot9cip2+DZEdEbHKnh6GjZoZHzjFVMMbCYrSFd1ZCoNgHE1AO1EVn0aYyhXcgAPY9PzxSgqAH0r2-xIE6wz2jk5FTkJigABJkJFJmonC53F5PFURkEQmE2KR0J4wRCSvDGuRgrl8gBmNgAK2QMSWpioiGi9FIiCO+GsNkgAE8AKKwPS0RkkUhUcj0bQvN7yIGmd5gYhkfmCj4HeBHR4wFmuXYfACOzCQ0GCTFIhVFyyg0W4WEQG2lAu0XB4fAuytVx3QWDp8AcgKNrKsRpWfKtHxFYuZYLdaslkAAXjR0HRUG6dh6bMzoCqw5BNdrdTqDUHTPBrqRkBsddBBtotghyOR82AABRlACU8iN-wgieNMTIDMl-zkQA Open this visualization in the Vega Editor>--@-let trans = transform-              . filter (FExpr \"datum.Cluster[0] == \'C\'\")--    errorEnc = encoding-                . position Y [ PName \"plx\"-                             , PmType Quantitative-                             , PScale [SZero False]-                             , PAxis [ AxTitle \"parallax (mas)\" ]-                             ]-                . position 'YError' [ PName \"e_plx\" ]-                . position X [ PName \"Gmag\", PmType Quantitative ]-                . column [ FName \"Cluster\", FmType Nominal ]--in toVegaLite [ gaiaData-              , trans []-              , errorEnc []-              , mark 'ErrorBar' []-              ]-@--}--errorAuto :: VegaLite-errorAuto =-  let trans = transform-                . filter (FExpr "datum.Cluster[0] == 'C'")-  -      errorEnc = encoding-                  . position Y [ PName "plx"-                               , PmType Quantitative-                               , PScale [SZero False]-                               , PAxis [ AxTitle "parallax (mas)" ]-                               ]-                  . position YError [ PName "e_plx" ]-                  . position X [ PName "Gmag", PmType Quantitative ]-                  . column [ FName "Cluster", FmType Nominal ]--  in toVegaLite [ gaiaData-                , trans []-                , errorEnc []-                , mark ErrorBar []-                ]----{-|--In this plot the error range is calculated by Vega-Lite,-and is taken from the standard deviation of the @Gmag@ field-('StdDev'). The 'MTicks' and 'MRule' constructors are used to-color the different parts of the error bars. Since the error bar-does not reference the central value, a separate layer is used-to add a square symbol ('SymSquare') at the average ('Mean')-value of the distribution.--<<images/vl/errorbars.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFACYCGKpGYoEEkArgE4A2VMKKADgM7oD0fRqQDuAOkTwU0egCN63WIwDGAewB2KWBtGqAtnwAiK+ogBCTANaw+0AG6xEpPrtLdNjG-cd8yFPo-hSAFpSYIA2AEYwkIicIIoZZlgI0lE1FSC4UmJFURRuW0hCWigAMxVGFzRMYEhOUkYFKlqAcRdENjV6XRlFIqhOZgAPTu7exn7IWAB9QZHMSC6evoBfFaIV4qhheGIpKlwCIkgAEm4lOBc2VC5eAS9UiSlZUXgVPnPLpweg5klrWxYUQAK246iKx2YpAAnn1MABtIgQGglKAuRgWZpI1GQRj0JLNSCqZgVNiaUisTbYkpTIaaDRsNw5QpbVFQFDQziwNiKRgVGQNCFsugoeBKCzcQnE0kLThMQbc9ZsqlsqZqVTEeBqDo1am0SDQwmleCwZjENhtUgdfBQc4U7k1SAAL0UKiopQpCk27M5DqgAEd6KQNJJyPB7JAlaioxAVbQUTT0ZjHdx4C6qAAmAi26CkLmMwMNbk2yAc-OylRatBxmlaDVanXUPV0Q2O42m80LS3WqBWxCMBzkP2QXSwYOTMvDwshiiiiMx2gLqMAXS2avr2sJ82okHbZrYAGFmPJ3BPfZ0VLotRTI3GiepjY3gOsVkA Open this visualization in the Vega Editor>--@-let cluster = position X [ PName \"Cluster\", PmType Nominal ]-             -    barOpts = [ 'MExtent' 'StdDev'-              , 'MTicks' [ 'MColor' \"purple\" ]-              , 'MRule' [ MColor \"teal\" ]-              ]-    range = [ mark ErrorBar barOpts-            , encoding-                . position Y [ PName \"Gmag\"-                             , PmType Quantitative-                             , PScale [ SZero False ]-                             ]-                $ []-            ]--    center = [ mark Point [ 'MShape' 'SymSquare', 'MSize' 20 ]-             , encoding-                 . position Y [ PName \"Gmag\"-                              , PmType Quantitative-                              , PmType 'Mean'-                              ]-                 $ []-             ]--in toVegaLite-      [ gaiaData-      , encoding (cluster [])-      , layer (map asSpec [ range, center ])-      , width 300-      , height 300-      ]-@---}--errorBars :: VegaLite-errorBars = -  let cluster = position X [ PName "Cluster", PmType Nominal ]-             -      barOpts = [ MExtent StdDev-                , MTicks [ MColor "purple" ]-                , MRule [ MColor "teal" ]-                ]-      range = [ mark ErrorBar barOpts-              , encoding-                  . position Y [ PName "Gmag"-                               , PmType Quantitative-                               , PScale [ SZero False ]-                               ]-                  $ []-              ]--      point = [ mark Point [ MShape SymSquare, MSize 20 ]-              , encoding-                  . position Y [ PName "Gmag"-                               , PmType Quantitative-                               , PAggregate Mean-                               ]-                  $ []-              ]--  in toVegaLite-      [ gaiaData-      , encoding (cluster [])-      , layer (map asSpec [ range, point ])-      , width 300-      , height 300-      ]---{-|-The next plot shows the 'ErrorBand' mark, which fills the area between-the chosen range with a color, and optional borders. Here the-blue band shows the calculated standard deviation - as used in-'errorBars' - and the gray band with borders shows the inter-quartile-range. On top of these are drawn the median (blue) and median (green-dashed) lines.--<<images/vl/errorband.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFACYCGKpGYoEEkArgE4A2VMKKADgM7oD0fRqQDuAOkTwU0egCN63WIwDGAewB2KWBtGqAtnwAiK+ogBCTANaw+0AG6xEpPrtLdNjG-cd8yFPo-hSAFpSYIA2AEYwkIicIIoZZlgI0lE1FSC4UmJFURRuW0hCWigAMxVGFzRMYEhOUkYFKlqAcRdENjV6XRlFIqhOZgAPTu7exn7IWAB9QZHMSC6evoBfFaIV4qhheGIpKlwCIkgAEm4lOBc2VC5eAS9UiSlZUXgVPnPLpweg5klrWxYUQAK246iKxxQkiSbAAwipdPVGPA1IgwEJUbBuBC6MxSABPPqYADaRAgNBKUBcjAszSmQ00GjYbhyhXwUBQ+M4sDYikYFRkpDUxEgmzJtCmalUxBRHRq4pKkHxdNK8FgzBFCzapA67Mg51IMJqkAAXooVFRSoaFJsOVyeQsAI70IVQihQ+yihVgdYlMUlCmK6m0+WUiUyCo5Rp0tz8qwGVzQKjEsLsgBMAF1-WGoKpmBU2IghMqtmH6YzqlB4I6JqXKZBOdzeYx+YxBcLIN7s4qtNLZc1vXRlcbVerNVBtbqoAajdRTebLdbYLaG-a2M7XZJyPBPb7KXuIN3qN7IMG2H81Dy63ReyoZaiBzmoMPj0+6KONWxJzi3-qlIaHTnM1+UXZgbWvesdSLBxyEA09YBlIUfyfVcmydF0NC3D0eUHH0u3FI9AwlM9jTzAsFmgrRJljFR40TZNUzANN2QAFnTDM9UbOCLx5I8bylO9+1DHMlUfX8P3HSBvwgxUZ0A2pgItTArTA5cZIlKDGBgzQ2F0WAkPUuguPXDC3W3T1cIPWgrL3Djjlve85TneY5wkuFmHkdxJmMhZ0l0FFDVFbNIFUNRVSc4B1hWIA Open this visualization in the Vega Editor>--@-let posY extra = position Y ([ PName \"Gmag\"-                             , PmType Quantitative-                             , PScale [ SZero False ]-                             ] ++ extra) []-           -    bands = [ [ encoding (posY [])-              , mark 'ErrorBand' [ MExtent StdDev ]-              ]-            , [ encoding (posY [])-              , mark ErrorBand [ MExtent 'Iqr'-                               , 'MBorders' [ 'MStrokeDash' [ 6, 2 ] ]-                               , MColor "gray"-                               ]-              ]-            , [ encoding (posY [ PAggregate Median ])-              , mark Line []-              ]-            , [ encoding (posY [ PAggregate Mean ])-              , mark Line [ MColor \"green\"-                          , MStrokeDash [ 6, 2, 4, 2 ]-                          ]-              ]-            ]-           -in toVegaLite-    [ gaiaData-    , encoding (position X [ PName \"Cluster\", PmType Nominal ] [])-    , layer (map asSpec bands)-    , width 300-    , height 300-    , title "Comparing ranges" []-    ]-@--Note that I don't think this is a good visualization-for this /particular/ dataset, since it implies there's a-connection or correlation between clusters, as given by the-x-axis ordering, but the aim here is to show how to use @hvega@-rather than creating sensible plots!---}--errorBand :: VegaLite-errorBand = -  let posY extra = position Y ([ PName "Gmag"-                               , PmType Quantitative-                               , PScale [ SZero False ]-                               ] ++ extra) []-             -      bands = [ [ encoding (posY [])-                , mark ErrorBand [ MExtent StdDev ]-                ]-              , [ encoding (posY [])-                , mark ErrorBand [ MExtent Iqr-                                 , MBorders [ MStrokeDash [ 6, 2 ] ]-                                 , MColor "gray"-                                 ]-                ]-              , [ encoding (posY [ PAggregate Median ])-                , mark Line []-                ]-              , [ encoding (posY [ PAggregate Mean ])-                , mark Line [ MColor "green"-                            , MStrokeDash [ 6, 2, 4, 2 ]-                            ]-                ]-              ]-             -  in toVegaLite-      [ gaiaData-      , encoding (position X [ PName "Cluster", PmType Nominal ] [])-      , layer (map asSpec bands)-      , width 300-      , height 300-      , title "Comparing ranges" []-      ]---{-|--An alternative visualization of a distribution is the \"box and-whiskers\" plot, which can be achieved in @hvega@ with the-'Boxplot' mark. The example below shows the default settings, but-the various components can be controlled with 'MBox', 'MMedian',-'MOutliers', and 'MTicks'.--<<images/vl/errorbox.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQBGA9gB4AOANvWoRJACakqkaoCNwCu5VjRgoUzAM7oA9IvKkA7gDpE8FNFG1Rc2OQDG9AHYpYljWeKKAIvVGIAQuMqxF0AG6xEpIpkclbk3n4BinwCigHwpAC0pIkAbACMKUlpOAkCtKywaaQa5vQJcKQ8xhoocj6QXCKQAGb05GRomMCQzBRGQpAA4mSIUuaixLTGDVBsjGMTU+QzkLAA+nMLk9MAvjtEO42QavA8ujS4BESQACRyJnBkUqiyCsoRxdq6+hrw9Ir3R6BD4JVg6Lw+LAaABWcgsDWu1jMPHg5lGXSI3HmXRa8FgrB4UgAwqxDKEVigAJ7MWBjejEVGkSSHTFQSkDZp4glSYakUb4KBUmlSACOolIlh0-Hgfkg+wgLO4ZnMnPRYGA+x2QA Open this visualization in the Vega Editor>--@-toVegaLite-    [ gaiaData-    , encoding-        . position X [ PName \"Cluster\", PmType Nominal ]-        . position Y [ PName \"Gmag\", PmType Quantitative ]-        $ []-    , mark 'Boxplot' []-    , width 300-    , height 300-    ]-@--The 'Boxplot' option supports two different \"ranges\":-- * the default is the Tukey Box plot, where the whiskers span-   a range @Q1 - k * IQR@ to @Q3 + k * IQR@, @IQR = Q3 - Q1@,-   @Q1@ and @Q3@ are the lower and upper inter-quartile values-   (so 25 and 75 per cent of the distribution), and @k@-   defaults to 1.5 but can be changed with 'IqrScale';-- * or 'ExRange', which uses the full range of the data (i.e.-   minimum to maximum values).---}--errorBox :: VegaLite-errorBox = -  toVegaLite-      [ gaiaData-      , encoding-          . position X [ PName "Cluster", PmType Nominal ]-          . position Y [ PName "Gmag", PmType Quantitative ]-          $ []-      , mark Boxplot []-      , width 300-      , height 300-      ]---{-|--Here I combine 'errorBox' with 'smallMultiples2' so we can compare-the distribution (from the histogram) with that from the box plot.--<<images/vl/comparingerrors.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCEwJBksDgCBZAA4iYshJBiWLLcgqlQZHgAHrX1jc0pUPwA+m2dqHUNTTiQAL5T6VNpmBRk-EIF6Zh4sACezagA2usY6BgnkCY4GrXcJamHp1Ki0GxiNajHJ6eieDnlmWz8eGgtQAwng+OYWpB4Ftll0RLJnrACH1IMEWFIgah6ng8PM7h9ICM0Fl-oDalVYDUUdxnoR4DgsPwUdDYaMAI5YWASDgINj6aYLD6nLZrIVCyCUlg4AwIfi1URYCS3MUElly9mc7mIeB8uWClWYWDtNgUco6+DBWoAOXGgjAIkyYAAyohStN8SdZiqvR88UL3gTzpc3h6MrJ+E8ueUvj9RkFYEJLn6DZBuCIiYUzDgRFpagwiBw5cmVZBlBb-m7UJkkQJ9WKoTD1VA0+02iJ8qHiwSHiIni9RSmY5M3iSAZioKDwb0oGq4QixEjIWiMYRsbi6+KM6OyaMKVSZ43ahyuebefyu+KRSPdEjGYQABy+H1C58YV8AXTmgsgABIKEJohMWoSHIKhaCsMJ2E4HgmDYERqH-QCjAgpw8ELahdAAZiYAArChxGVKAvgaMRTVQAAWb9qyEfh8hHP4xxBMEzGnBtWSgCJ50XZNIFEMQ-leNBZimIA Open this visualization in the Vega Editor>--@-let histEnc = encoding-                . position X [ PName \"Gmag\", PmType Quantitative, PBin [] ]-                . position Y yAxis-                . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]--    errEnc = encoding-               . position X [ PName \"Gmag\", PmType Quantitative ]-               . position Y [ 'PNumber' 80 ]-               . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]-    -    yAxis = [ PAggregate Count-            , PmType Quantitative-            , PAxis [ AxTitle \"Number of Stars\" ]-            ]--    boxOpts = [ 'MMedian' [ MColor \"black\" ]-              , 'MBox' [ MStroke \"white\" ]-              , 'MNoOutliers'-              ]-    -    histSpec = asSpec [ mark Bar [], histEnc [] ]-    errSpec = asSpec [ mark Boxplot boxOpts, errEnc [] ]--    combinedSpec = asSpec [ layer [ histSpec, errSpec ] ]-    -in toVegaLite-    [ gaiaData-    , columns 4-    , facetFlow [ FName \"Cluster\", FmType Nominal ]-    , specification combinedSpec-    ]-@--The main additions here are the configuration of the box plot - with-'MMedian', 'MBox' (used to ensure the box is visually distinct from-the bar for the Pleiades cluster, where they overlap), and 'MNoOutliers'-(to turn off the display of the outliers) - and the use of 'PNumber'-to define the location on the y axis of the boxplot visualization.-Note that 'PNumber' is defined in pixel units, with 0 being the-top of the visualization and 80 was found by trial and error.---}--comparingErrors :: VegaLite-comparingErrors =- let histEnc = encoding-                . position X [ PName "Gmag", PmType Quantitative, PBin [] ]-                . position Y yAxis-                . color [ MName "Cluster", MmType Nominal, MLegend [] ]--     errEnc = encoding-                . position X [ PName "Gmag", PmType Quantitative ]-                . position Y [ PNumber 80 ]-                . color [ MName "Cluster", MmType Nominal, MLegend [] ]-     -     yAxis = [ PAggregate Count-             , PmType Quantitative-             , PAxis [ AxTitle "Number of Stars" ]-             ]--     boxOpts = [ MMedian [ MColor "black" ]-               , MBox [ MStroke "white" ]-               , MNoOutliers-               ]-     -     histSpec = asSpec [ mark Bar [], histEnc [] ]-     errSpec = asSpec [ mark Boxplot boxOpts, errEnc [] ]--     combinedSpec = asSpec [ layer [ histSpec, errSpec ] ]-     - in toVegaLite-     [ gaiaData-     , columns 4-     , facetFlow [ FName "Cluster", FmType Nominal ]-     , specification combinedSpec-     ]----- $intro-dashboard--- In the following visualization I try to combine as many of the--- concepts we have explored in this tutorial into one. There are--- layers, combined visualizations, and a selection that ties the--- different plots together.--{-|--This is based on the-<https://vega.github.io/vega-lite/examples/concat_marginal_histograms.html Marginal Histogram>-example from the Vega-Lite-<https://vega.github.io/vega-lite/examples/ Example Gallery>.-There is very-little new in this plot, in that pretty-much everything-has been shown before. However, there are some interesting wrinkles,-such as--  * combining multiple plots, in this case the \"top\" area - which is-    a histogram on top of a plot which is itself a \"map\" and-    a histogram - and \"bottom" area - which is just a point plot --    requires judicious use of 'asSpec';--  * selection works in __both__ the main plots - the \"map\" and \"point\"-    plots - to highlight all stars in the same cluster, and I was-    pleasantly surprised to find out I could just use the same selection-    specification (@selCluster@) in both (hopefully I am not just-    ejnoying a hole in the Vega Lite specification);--  * I have been perhaps too defensive in defining the Right Ascension-    and Declination axes in the relevant plots, as I want to make sure-    the histogram bins and plot axes are well aligned (that is the-    @'Nice' False@ statements may not be needed when defining the-    histogram axes);--  * I am not 100% sure I understand what is going on with the-    grid labels on the Declination axis, as I had thought I was-    asking for marks every 15 degrees, but the plot shows them-    every 30 degrees (however, if I change the @deTicks@ array then-    the marks change in ways I currently do not understand);--  * and I have decided to display Right Ascension in hours, rather than-    degrees, because why have one way to measure a value when you can-    have many!--<<images/vl/combinedplot.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJ5k8oAlAQUgBooBjeAGwYFdn5oBTcyAEy5ssAOmoB9AJIBhCgGUwAejABGAKyQAvgF1a4RukSoAlgHNyxAG7HuAdwuRkcdAGte+GAhQAHeLG6I0FqaehACXPAW+mFssMx8ABbQ0N7IuIqKCLYipsbQCWwARmzI3LAMhjyBIhVYigAi6GymAEKxbooJltym8IpYpDywnd29ioLQfb3G8AC08HMAbCqL8yoADLOThczcKvAiiOizCdzw-GUi0MiWdNFQGNhcDr6wpQ4A4gPmHojChWU6FBvMwAB58P5YAGwIGQbjiEHg37-QGaTT6EL6SCWCqIJhBfAEe6gCCkqA4wz48hEslkkm0smQU5mJLkDbrUIM0mQWzGfj5cgAFnWHPuDMgnAAnoDCWKufSubTIANYC4HBVmJg+KYEJLYdBJd53FBCn4tJzFYyAhV+MZED8wArLYykY65c6wiZuMx+HxqHcPVzIIU7Q5uKCqgTCBywAAmQW6KBObjecix+iQRDGBjG1AsUqYwPi5CYKMCbjIHOIW32gNFxkGo18ACObCQ0DyXGM3Tr9bC8FBxjI+D+zGY7sthb7kD1+Cd9ccTF2Dn46AGocJMYAzCL1top32oPBTDqelxjZAKmxAr3p42L63252Oz2LdOB0OHB3oMuRxxmOih6AUWwHOgelrzpanhIGgmA4ISxAmMwQwOKUuwMB2hh8N42ZqmiugTuKKpqh4powm+zpwni6A1g6kGURqWpzoRUGWCwbAXqeeoUUWl6GLamGIFEh6Ml6Pp8NIzAlChPELmh3AYcYWEeDhDBqrJvH3hCa52iwkAsYqoEgRpiqQK69EepAYm+h4-omVBIZCXOcIRgEUYEDG8aJo4PCpvg6ZQFmObkHmzAFvZpklrAZYXJWAS0beC5aR4j6BM+3a8BFQYfsOYCjuOQFZYys5uiJSZLsaxCruuTnRvQO4ivuRVKsep69DwfBXjezUNoaD5tmlkwvplBnZYOuXEN+v55f+RmBnNk6jQtZLaBO4F0ixTK4lSsqBhZ4rMqYrL4MKooLsRDjoL4DB5CV6wiGoGbJYwxjlMu61Qby-IJEKIrNY43oKYJLy4V+fV8MgdqmMuGbWblBCQJJ0mAvuH2mdaNFQ8J06MTCzFldi7Gcf43GjeKuICUptX7ZZ1kSVJybkWTQbyYpynAqDPVKs9mY6YgenM2Sy2TlzZnY4eVk2OJtk0FzYSViwlUCGu8AbnVcYJhmQW5vm3Bo5ZUUxRWVYJXLUA86l35dq+gvcjlX55NNkAUCy0BgFQcUoFTYAABQJE0bwAJRaLb+umSVNOmXTHj1AAolIshyIlvEK9NVUq2rBCzAAnDGufedrIW62HUEWwNVvDcngYkON4siYTUkVtStsMjnZ1laSswAOyPS3tKzIs7cd2AsyCr3w8QLMO5m2SszqDPpJDx38992S0+r6SY8LxAg-b2APd77nG8EcPMCOxe9QKcwumCb7FynhWwd98LhnMy-pIlxAkfcodx1gKd-0voCnwOyf6UoZSEFtt-IifgSKOj4pqPGUAdTwG4ubcGpEzSfyDBjBK+MO5i3wafVOStqqq1qh5equ4mob37Cefw7ULxdSCHvGAGCoCW3SjbCeR5a7OSmsafK78wILxnHXAm0coBxwTvIKu05HJhlcjeQkbd6D5wzMmPyqhHqBWzDrMKetWFlyfENDKciFz2z-GODewiuS2KFlzaB3MvCwWwNSRCxhkIQOIKzYGKlQb4TNsqWBfAyLmKgrgrGRD6643EfXNijdtQk3CdXCmeQqZxIkVLGyUAkaMxSSnQGbNaqQFUupWh3IeZHCwLpeIFT7F2NEeZCpi5FYrgzhQ7c1DsGUVagw88nUmjdRacYwa1sRo8Jrp+fh59yBCJsaIiOLTJGQGkTIWRrCFHOXDJGakqiwDqKTL5NkOjMx6KLgYnppd2GQE4aY7hE8pm5XyjY5+odmarXmixE+UFkDXSiXGJe4pChDP4LlKyDMfprTlD8xkfz4A3VrP5IFJpQXgtQJC-SDjiRymCaqS6-yDTkHuqcnmN03q8A+jyPkwCwBqFjCigG6E-HwLKWDJsHhIb2hhg8bJ8NEYMxQqjHiVEbQAosggpipVWJEySdwUmDF+LpPZt-SW3ockCuRkzauviMn+LUgUthHLAp8wFmBNaGlCHSqjtk7CYJwmtLTkai8mpzBa3OfgUK4VNqjIrmY+yTyHY-gvK8FgnBQS+xqWOYw8xyilApsHYW+sxHRPFCsr4x4HW+q4RMqClj4ECL4B8MA3wszQDYBcEOr8GRGWAj8yAAASSspwBiJGSKkdIihRgHFyPkIoIglKKGbdwAYXazyzGvjwLtW4RAACsSxCU5GfYNX4dlFtVvAMAExN2oFgGuMAfgAAa3ZcAqAABzrEFCIdY2ctxdzPbCJADB-ZIOVHyfg70QCaCAA Open this visualization in the Vega Editor (although the link is long, and may not work with Internet Explorer)>--@-let trans = transform-              . calculateAs \"datum.RA_ICRS / 15\" \"RA\"-              -    quant n = [ PName n, PmType Quantitative ]--    big = 400-    small = 100-    wmain = width big-    hmain = height big-    wsub = width small-    hsub = height small-    noTitle = PAxis [ AxNoTitle ]-    -    raAxis = [ PScale [ SDomain (DNumbers [ 0, 24 ])-                      , SNice (IsNice False)-                      ]-             , PSort [ Descending ]-             , PAxis [ AxTitle \"Right Ascension (hours)\" ]-             ]--    deMin = -90-    deMax = 90-    deStep = 15--    -- we do not get ticks/grids at all these values, but it does-    -- something (e.g. if do not specify the axis ticks are different)-    ---    deTicks = Numbers [ deMin, deMin + deStep .. deMax ]-    deAxis = [ PScale [ SDomain (DNumbers [ deMin, deMax ])-                      , SNice (IsNice False)-                      ]-             , PAxis [ AxTitle \"Declination (degrees)\"-                     , AxValues deTicks-                     ]-             ]--    colorEnc = color [ MSelectionCondition (SelectionName \"pick\")-                         [ MName \"Cluster\", MmType Nominal ]-                         [ MString \"grey\" ]-                     ]-    mapEnc = encoding-               . position X (quant \"RA\" ++ raAxis)-               . position Y (quant \"DE_ICRS\" ++ deAxis)-               . colorEnc--    circleMark = mark Circle [ MOpacity 0.5 ]-    -    mapSpec = asSpec [ mapEnc []-                     , circleMark-                     , wmain-                     , hmain-                     , selCluster []-                     ]--    -- histogram of the RA values-    ---    raBinning = [ PBin [ 'Extent' 0 24-                       , Step 2-                       , Nice False-                       ]-                , PSort [ Descending ]-                , PAxis []-                ]-                -    -- histogram of the Declination values-    ---    deBinning = [ PBin [ Extent deMin deMax-                       , Step deStep-                       , Nice False-                       ]-                , PAxis []-                ]--    histAxis = [ PAggregate Count-               , PmType Quantitative-               , noTitle-               , PScale [ SDomain (DNumbers [ 0, 3000 ]) ]-               ]-    -    raEnc = encoding-              . position X (quant \"RA\" ++ raBinning)-              . position Y histAxis-              -    deEnc = encoding-              . position Y (quant \"DE_ICRS\" ++ deBinning)-              . position X histAxis--    allRA = [ raEnc []-            , mark Bar [ MColor \"gray\" ]-            ]-    filtRA = [ filterCluster []-             , raEnc-                 . colorEnc-                 $ []-             , mark Bar []-             ]-             -    allDE = [ deEnc []-            , mark Bar [ MColor \"gray\" ]-            ]-    filtDE = [ filterCluster []-             , deEnc-                 . colorEnc-                 $ []-             , mark Bar []-             ]--    raSpec = asSpec [ wmain, hsub, layer [ asSpec allRA, asSpec filtRA ] ]-    deSpec = asSpec [ hmain, wsub, layer [ asSpec allDE, asSpec filtDE ] ]--    borderSpacing = 20--    mapAndDecSpec = asSpec [ spacing borderSpacing-                           , 'bounds' 'Flush'-                           , 'hConcat' [ mapSpec, deSpec ]-                           ]-    -    histSpecs = [ raSpec, mapAndDecSpec ]--    -- select the cluster which the star belongs to; do not use-    -- \"nearest click\" as that means a user can not cancel the-    -- selection.-    ---    pick = \"pick\"-    selCluster = selection-                   . select pick Single [ Fields [ \"Cluster\" ] ]--    filterCluster = transform-                      . filter (FSelection pick)--    plxOpts = [ PScale [ SType ScLog, SNice (IsNice False) ]-              , PAxis [ AxTitle \"parallax (milli-arcsecond)\" ]-              ]-    gmagOpts = [ PAxis [ AxTitle \"G magnitude\" ] ]-    -    encData = encoding-                . position X (quant \"plx\" ++ plxOpts)-                . position Y (quant \"Gmag\" ++ gmagOpts)--    parallaxSpec = asSpec [ width (big + borderSpacing + small)-                          , encData-                              . colorEnc-                              $ []-                          , circleMark-                          , selCluster []-                          ]-    -    allSpecs = [ asSpec [ spacing borderSpacing-                        , bounds Flush-                        , vConcat histSpecs-                        ]-               , parallaxSpec ]-                 -    -in toVegaLite-   [ gaiaData-   , trans []-   , vConcat allSpecs-     -- remove the "other" axis (e.g. top of Y, right for X)-   , configure-       . configuration ('View' [ 'ViewStroke' (Just \"transparent\") ])-       $ []-   , title \"Gaia data from arXiv:1804.09378\" [ 'TAnchor' 'AMiddle' ]-   ]-@--Here is the visualization after selecting a star:--<<images/vl/combinedplot-selected.png>>---}--combinedPlot :: VegaLite-combinedPlot =-  let trans = transform-                . calculateAs "datum.RA_ICRS / 15" "RA"-                -      quant n = [ PName n, PmType Quantitative ]--      big = 400-      small = 100-      wmain = width big-      hmain = height big-      wsub = width small-      hsub = height small-      noTitle = PAxis [ AxNoTitle ]-      -      raAxis = [ PScale [ SDomain (DNumbers [ 0, 24 ])-                        , SNice (IsNice False)-                        ]-               , PSort [ Descending ]-               , PAxis [ AxTitle "Right Ascension (hours)" ]-               ]--      deMin = -90-      deMax = 90-      deStep = 15--      -- we do not get ticks/grids at all these values, but it does-      -- something (e.g. if do not specify the axis ticks are different)-      ---      deTicks = Numbers [ deMin, deMin + deStep .. deMax ]-      deAxis = [ PScale [ SDomain (DNumbers [ deMin, deMax ])-                        , SNice (IsNice False)-                        ]-               , PAxis [ AxTitle "Declination (degrees)"-                       , AxValues deTicks-                       ]-               ]--      colorEnc = color [ MSelectionCondition (SelectionName "pick")-                           [ MName "Cluster", MmType Nominal ]-                           [ MString "grey" ]-                       ]-      mapEnc = encoding-                 . position X (quant "RA" ++ raAxis)-                 . position Y (quant "DE_ICRS" ++ deAxis)-                 . colorEnc--      circleMark = mark Circle [ MOpacity 0.5 ]-      -      mapSpec = asSpec [ mapEnc []-                       , circleMark-                       , wmain-                       , hmain-                       , selCluster []-                       ]--      -- histogram of the RA values-      ---      raBinning = [ PBin [ Extent 0 24-                         , Step 2-                         , Nice False-                         ]-                  , PSort [ Descending ]-                  , PAxis []-                  ]-                  -      -- histogram of the Declination values-      ---      deBinning = [ PBin [ Extent deMin deMax-                         , Step deStep-                         , Nice False-                         ]-                  , PAxis []-                  ]--      histAxis = [ PAggregate Count-                 , PmType Quantitative-                 , noTitle-                 , PScale [ SDomain (DNumbers [ 0, 3000 ]) ]-                 ]-      -      raEnc = encoding-                . position X (quant "RA" ++ raBinning)-                . position Y histAxis-                -      deEnc = encoding-                . position Y (quant "DE_ICRS" ++ deBinning)-                . position X histAxis--      allRA = [ raEnc []-              , mark Bar [ MColor "gray" ]-              ]-      filtRA = [ filterCluster []-               , raEnc-                   . colorEnc-                   $ []-               , mark Bar []-               ]-               -      allDE = [ deEnc []-              , mark Bar [ MColor "gray" ]-              ]-      filtDE = [ filterCluster []-               , deEnc-                   . colorEnc-                   $ []-               , mark Bar []-               ]--      raSpec = asSpec [ wmain, hsub, layer [ asSpec allRA, asSpec filtRA ] ]-      deSpec = asSpec [ hmain, wsub, layer [ asSpec allDE, asSpec filtDE ] ]--      borderSpacing = 20--      mapAndDecSpec = asSpec [ spacing borderSpacing-                             , bounds Flush-                             , hConcat [ mapSpec, deSpec ]-                             ]-      -      histSpecs = [ raSpec, mapAndDecSpec ]--      -- select the cluster which the star belongs to; do not use-      -- "nearest click" as that means a user can not cancel the-      -- selection.-      ---      pick = "pick"-      selCluster = selection-                     . select pick Single [ Fields [ "Cluster" ] ]--      filterCluster = transform-                        . filter (FSelection pick)--      plxOpts = [ PScale [ SType ScLog, SNice (IsNice False) ]-                , PAxis [ AxTitle "parallax (milli-arcsecond)" ]-                ]-      gmagOpts = [ PAxis [ AxTitle "G magnitude" ] ]-      -      encData = encoding-                  . position X (quant "plx" ++ plxOpts)-                  . position Y (quant "Gmag" ++ gmagOpts)--      parallaxSpec = asSpec [ width (big + borderSpacing + small)-                            , encData-                                . colorEnc-                                $ []-                            , circleMark-                            , selCluster []-                            ]-      -      allSpecs = [ asSpec [ spacing borderSpacing-                          , bounds Flush-                          , vConcat histSpecs-                          ]-                 , parallaxSpec ]-                   -      -  in toVegaLite-     [ gaiaData-     , trans []-     , vConcat allSpecs-     -- remove the "other" axis (e.g. top of Y, right for X)-     , configure-         . configuration (View [ ViewStroke (Just "transparent") ])-         $ []-     , title "Gaia data from arXiv:1804.09378" [ TAnchor AMiddle ]-     ]---{---Other things to do:-- - add some description of magnitude / parallax meanings-   (since talk about astronomy being awkward)-- - tooltips---}-+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.Tutorials.VegaLite+Copyright   : (c) Douglas Burke, 2019-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings++This tutorial is inspired by - in that it starts off as a close copy of - the+<https://github.com/gicentre/elm-vegalite/tree/master/docs/walkthrough Elm Vega-Lite walkthrough>+created by Jo Wood, and+converted as necessary for the differences between @hvega@ and+<https://package.elm-lang.org/packages/gicentre/elm-vegalite/latest elm-vegalite>.+The Elm tutorial is based on the talk given by+<https://youtu.be/9uaHRWj04D4 Wongsuphasawat et al at the 2017 Open Vis Conf>.++The tutorial targets version 4 of the Vega-Lite specification and+the functionality provided in version @0.5.0.0@ of hvega.++-}++module Graphics.Vega.Tutorials.VegaLite (++  -- * A Grammar of Graphics+  --+  -- $intro++  -- ** How many Haskell extensions do you need?+  --+  -- $intro-extensions++  -- ** A note on type safety+  --+  -- $intro-type-safety++  -- ** Comparing hvega to Elm Vega-Lite+  --+  -- $compare-to-elm++  -- * What data are we using?+  --+  -- $datasource++  -- * Creating the Vega-Lite visualization+  --+  -- $output++  -- * A Strip Plot+  --+  -- $singleview-stripplot++  -- ** Our first hvega plot+  --+  stripPlot++  -- ** Backgrounds+  --+  -- $background-note++  , stripPlotWithBackground++  -- ** Challenging the primacy of the x axis+  --+  , stripPlotY++  -- ** Data sources+  --++  , gaiaData++  -- ** Adding color as an encoding++  , stripPlotWithColor++  -- ** Comparing Ordinal with Nominal data types+  --+  -- $stripplot-mmtype++  , stripPlotWithColorOrdinal++  -- * Adding an axis+  --+  -- $add-axis++  , parallaxBreakdown++  -- ** Creating a value to plot: aggregating data+  --+  -- $histogram++  , simpleHistogram+  , parallaxHistogram+  , gmagHistogram++  -- ** Changing the scale of an axis+  --+  -- $ylog-histogram++  , ylogHistogram++  -- ** Stacked Histogram++  , gmagHistogramWithColor+  , gmagLineWithColor++  -- ** You don't have to just count+  --+  -- $histogramChoice++  , yHistogram++  , starCount+  , starCount2++  , densityParallax+  , densityParallaxGrouped++  -- ** Plotting with points+  --+  -- $intro-points++  , pointPlot++  -- * Making a map+  --+  -- $intro-map++  , posPlot++  -- ** Using a projection++  , skyPlot++  -- ** Choropleth with joined data++  -- $intro-choropleth++  , choroplethLookupToGeo++  -- * Layered and Multi-View Compositions+  --+  -- $intro-layered++  , smallMultiples+  , smallMultiples2++  , densityMultiples++  -- ** One plot, two plot, red plot, blue plot+  --+  -- $intro-multiplot++  , basePlot++  -- ** Composing layers++  , layeredPlot+  , layeredDiversion+  , layeredCount+  , skyPlotWithGraticules++  -- ** Concatenating views++  , concatenatedPlot+  , concatenatedPlot2+  , concatenatedSkyPlot++  -- ** Repeated views+  --+  -- $intro-repeat++  -- *** Varying fields field++  , repeatPlot++  -- *** Repeating Choropleths++  , choroplethLookupFromGeo++  -- *** Rows and Columns+  , splomPlot++  -- * Interactivity+  --+  -- $intro-interactivity++  , selectionProperties+  , singleSelection+  , nearestSelection+  , multiSelection+  , eventSelection+  , intervalSelection+  , intervalSelectionY++  -- ** Selection Transformations+  --+  -- $intro-selection-transforms++  , transformSelection++  -- *** Selection and bindings+  --+  -- $intro-selection-binding++  , legendSelection+  , widgetSelection+  , bindScales++  -- *** Multiple Coordinated Views+  --+  -- $intro-coordinated-views++  , coordinatedViews+  , coordinatedViews2++  , contextAndFocus++  -- *** Cross-filtering+  --+  -- $intro-crossfilter++  , crossFilter++  -- * Smoothing and Regressing+  --+  -- $intro-smoothing++  , loessExample+  , regressionExample++  -- * Errors: lines, bars, bands, and boxes+  --+  -- $intro-error++  , errorManual+  , errorAuto++  , errorBars+  , errorBand+  , errorBox++  , comparingErrors++  -- * Dashboard-esque+  --+  -- $intro-dashboard++  , combinedPlot++  -- * The end+  --+  -- $otherstuff++  , duplicateAxis+  , compareCounts+  , parallaxView++  -- ** Aitoff projections+  --+  -- $aitoff++  , skyPlotAitoff+  , clusterCenters++  ) where++import qualified Data.Text as T++import Prelude hiding (filter, lookup, repeat)++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif++import Graphics.Vega.VegaLite++-- $intro+-- hvega is a wrapper for the [Vega-Lite visualization+-- grammar](https://vega.github.io/) which itself is based on Leland+-- Wilkinson's [Grammar of+-- Graphics](http://www.springer.com/gb/book/9780387245447).  The+-- grammar provides an expressive way to define how data are+-- represented graphically. The seven key elements of the grammar as+-- represented in hvega and Vega-Lite are:+--+-- [@Data@]: The input to visualize. Example functions: 'dataFromUrl', 'dataFromColumns', and 'dataFromRows'.+--+-- [@Transform@]: Functions to change the data before they are visualized. Example functions: 'filter', 'calculateAs', 'binAs', 'pivot', 'density', and+-- 'regression'. These functions are combined with 'transform'.+--+-- [@Projection@]: The mapping of 3d global geospatial locations onto a 2d plane . Example function: 'projection'.+--+-- [@Mark@]: The visual symbol, or symbols, that represent the data. Example types, used with 'mark': 'Line', 'Circle', 'Bar', 'Text', and 'Geoshape'. There are also ways to specify the shape to use for the 'Point' type, using the 'MShape' setting and the 'Symbol' type.+--+-- [@Encoding@]: The specification of which data elements are mapped to which mark characteristics (commonly known as channels). Example functions: 'position', 'shape', 'size', and 'color'. These encodings are combined with 'encoding'.+--+-- [@Scale@]: Descriptions of the way encoded marks represent the data. Example settings: 'SDomain', 'SPadding', and 'SInterpolate'.+--+-- [@Guides@]: Supplementary visual elements that support interpreting the visualization. Example setings: 'AxDomain' (for position encodings) and 'LeTitle' (for legend color, size, and shape encodings).+--+-- In common with other languages that build upon a grammar of graphics+-- such as D3 and Vega, this grammar allows fine grain control of+-- visualization design. Unlike those languages, Vega-Lite - and+-- hvega in turn - provide practical default specifications for most of the+-- grammar, allowing for a much more compact high-level form of+-- expression.+--+-- The [Vega-Lite Example Gallery](https://vega.github.io/vega-lite/examples/)+-- provides a large-number of example visualizations that show off+-- the capabilities of Vega-Lite. Hopefully, by the end of this+-- tutorial, you will be able to create most of them.++-- $intro-extensions+-- The 'Graphics.Vega.VegaLite' module exports a large number of symbols,+-- but does not use any complex type machinery, and so it can be loaded+-- without any extensions, although the extensive use of the 'Data.Text.Text'+-- type means that using the @OverloadedStrings@ extension is __strongly__+-- advised.+--+-- The module does export several types that conflict with the Prelude,+-- so one suggestion is to use+--+--     > import Prelude hiding (filter, lookup, repeat)++-- $intro-type-safety+-- The interface provided by @hvega@ provides __limited__ type safety. Various+-- fields such as 'PmType' are limited by the type of the argument (in this+-- case 'Measurement'), but there's no support to check that the type makes+-- sense for the particular column (as @hvega@ itself does not inspect the+-- data source). Similarly, @hvega@ does not stop you from defining+-- properties that are not valid for a given situation - for instance+-- you can say @'toVegaLite' []@ even though the output is not a+-- valid Vega-Lite specification (i.e. it does not validate against+-- the [Vega-Lite schema](https://github.com/vega/schema)).+--+-- Version @0.5.0.0@ did add some type safety for a number of functions -+-- primarily 'encoding' and 'transform' - as the types they accept+-- have been restricted (to @['EncodingSpec']@ and @['TransformSpec']@+-- respectively), so that they can not be accidentally combined.++-- $compare-to-elm+-- @hvega@ started out as a direct copy of+-- [elm-vegalite](https://package.elm-lang.org/packages/gicentre/elm-vegalite/latest),+-- and has been updated to try and match the functionality of that package.+-- However, @hvega@ has not (yet?) followed @elm-vegalite@ into using+-- functions rather than data structures to define the options: for+-- example, @elm-vegalite@ provides @pQuant n@ which in @hvega@ is the+-- combination of @'PName' n@ and @'PmType' 'Quantitative'@ in @hvega@.+-- The top-level functions - such as 'dataFromUrl', 'encoding', and+-- 'filter' - are generally the same.+--+-- Version @0.5.0.0@ does introduce more-significant changes, in that+-- there are now separate types for a number of functions - such as+-- 'encoding', 'transform', and 'select' - to help reduce the+-- chance of creating invalid visualizations.++-- $datasource+-- Rather than use the Seattle weather dataset, used in the Elm walkthrough+-- (if you go through the [Vega-Lite Example Gallery](https://vega.github.io/vega-lite/examples/)+-- you may also want to look at different data ;-), I am going to use a+-- small datset from the [Gaia satellite](http://sci.esa.int/gaia/),+-- which has - and still is, as of early 2020 - radically-improved our knowledge+-- of our Galaxy. The data itself is from the paper+-- \"Gaia Data Release 2: Observational Hertzsprung-Russell diagrams\"+-- [(preprint on arXiV)](https://arxiv.org/abs/1804.09378)+-- [(NASA ADS link)](https://ui.adsabs.harvard.edu/#abs/arXiv:1804.09378).+-- We are going to use Table 1a, which was downloaded from the+-- [VizieR archive](http://vizier.u-strasbg.fr/viz-bin/VizieR-3?-source=J/A%2bA/616/A10/tablea1a)+-- as a tab-separated file (aka 'TSV' format).+--+-- The file contains basic measurements for a number of stars in+-- nine open clusters that all lie within 250 parsecs of the Earth+-- (please note, a parsec is a measure of distance, not time, no matter+-- what [some ruggedly-handsome ex-carpenter](https://en.wikipedia.org/wiki/Han_Solo)+-- might claim). The downloaded file is called+-- @gaia-aa-616-a10-table1a.no-header.tsv@, although I have+-- manually edited it to a \"more standard\" TSV form (we Astronomers like+-- our metadata, and tend to stick it in inappropriate places, such as the+-- start of comma- and tab-separated files, which really mucks up+-- other-people's parsing code). The first few rows in the file are:+--+--+-- +-------------------+---------+-----------+-----------+--------+--------+-------++-- | Source            | Cluster | RA_ICRS   | DE_ICRS   | Gmag   | plx    | e_plx |+-- +===================+=========+===========+===========+========+========+=======++-- | 49520255665123328 | Hyades  | 064.87461 | +21.75372 | 12.861 | 20.866 | 0.033 |+-- +-------------------+---------+-----------+-----------+--------+--------+-------++-- | 49729231594420096 | Hyades  | 060.20378 | +18.19388 | 5.790  | 21.789 | 0.045 |+-- +-------------------+---------+-----------+-----------+--------+--------+-------++-- | 51383893515451392 | Hyades  | 059.80696 | +20.42805 | 12.570 | 22.737 | 0.006 |+-- +-------------------+---------+-----------+-----------+--------+--------+-------++-- | ...               | ...     | ...       | ...       | ...    | ...    | ...   |+-- +-------------------+---------+-----------+-----------+--------+--------+-------++--+-- The @Source@ column is a numeric identifier for the star in the Gaia database,+-- in this particular case the [\"DR2\" release](https://www.cosmos.esa.int/web/gaia/dr2),+-- the @Cluster@ column tells us which [Star Cluster](https://en.wikipedia.org/wiki/Star_cluster)+-- the star belongs to, @RA_ICRS@ and @DE_ICRS@+-- [locate the star on the sky](https://en.wikipedia.org/wiki/Celestial_coordinate_system)+-- and use the [Equatorial coordinate system](https://en.wikipedia.org/wiki/Equatorial_coordinate_system)+-- (the @ICRS@ term has a meaning too, but it isn't important for our+-- purposes),+-- @Gmag@ measues the "brightness" of the star (as in most-things Astronomical,+-- this is not as obvious as you might think, as I'll go into below),+-- and the @plx@ and @e_plx@ columns give the measured+-- [parallax of the star](https://en.wikipedia.org/wiki/Equatorial_coordinate_system)+-- and its error value, in units of+-- milli [arcseconds](https://en.wikipedia.org/wiki/Minute_and_second_of_arc).+-- And yes, I do realise after complaining about popular-culture references+-- confusing distances and time, I am now measuring distances with angles.+-- I think I've already mentioned that Astronomy is confusing...++-- $output+-- The function 'toVegaLite' takes a list of grammar specifications,+-- as will be shown in the examples below, and creates a single JSON object+-- that encodes the entire design. As of @hvega-0.5.0.0@ this targets+-- version 4 of the Vega-Lite schema, but this can be over-ridden with+-- 'toVegaLiteSchema' if needed (although note that this just changes the+-- version number in the schema field, it does not change the output to+-- match a given version).+--+-- There is no concept of ordering to these specification lists, in that+-- @[ dataFromUrl ..., encoding ..., mark ...]@;+-- @[ encoding ..., dataFromUrl ..., mark ... ]@;+-- and+-- @[ encoding ..., mark ..., dataFromUrl ... ]@+-- would all result in the same visualization.+--+-- The output of 'toVegaLite' can be sent to the Vega-Lite runtime to+-- generate the Canvas or SVG output. @hvega@ contains the helper+-- routines:+--+--  * 'fromVL', which is used to extract the JSON contents from 'VegaLite'+--    and create an Aeson 'Data.Aeson.Value';+--+--  * 'toHtml', which creates a HTML page which uses the+--    <https://github.com/vega/vega-embed Vega Embed> Javascript+--    library to display the Vega-Lite visualization;+--+--  * and 'toHtmlFile', which is like 'toHtml' but writes the output+--    to a file.++-- $singleview-stripplot+-- In this section we shall concentrate on creating a single+-- plot. Later on we shall try combining plots, after branching+-- out to explore some of the different ways to visualize+-- multi-dimensional data sets.+--+-- In the examples I link to symbols that have not been used in+-- previous visualizations, to make it easier to see the use+-- of new functionality.++{-|++We could encode one of the numeric data fields as a strip plot where+the horizontal position of a tick mark is determined by the value+of the data item. In this case I am going to pick the "@plx@" column:++<<images/vl/stripplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CmBIdABPDgVmPIKAX0JWoqgAEi5sDLhmNk4efndkiSlZEUwVXj6Bh3H-BklLawBmEQArLnVCwkgtVSJMNTFqyAAPS5LMBQYiZg4GG7wMBqa0SABHWlgNJJSJhbJBWp1Dqo1HcLmhgO1WkA Open this visualization in the Vega Editor>++@+'toVegaLite'+    [ 'dataFromUrl' "https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv" ['TSV']+    , 'mark' 'Tick' []+    , 'encoding' ('position' 'X' [ 'PName' "plx", 'PmType' 'Quantitative' ] [])+    ]+@++Notice how there is __no explicit definition__ of the axis details,+color choice or size. These can be customised, as shown in examples+below, but the default values are designed to follow good practice in+visualization design.++Three grammar elements are represented by the three functions+'dataFromUrl', 'mark', and 'encoding'.++The 'encoding' function takes as a single parameter, a list of+specifications that are themselves generated by other functions. In+this case we use the function 'position' to provide an encoding of the+@\"plx\"@ field as the x-position in our plot. The precise way in which+the data value (parallax) is mapped to the x-position will depend on the type of+data we are encoding. We can provide a hint by delcaring the+measurement type of the data field, here 'Quantitative' indicating a+numeric measurement type. The final parameter of position is a list of+any additional encodings in our specification. Here, with only one+encoding, we provide an empty list.++As we build up more complex visualizations we will use many more+encodings. To keep the coding clear, the idiomatic way to do this with+hvega is to chain encoding functions using point-free+style. The example above coded in this way would be++@+let enc = encoding+            . position X [ PName "plx", PmType Quantitative ]++in toVegaLite+    [ dataFromUrl "https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]+    , mark Tick []+    , enc []+    ]+@++-}++stripPlot :: VegaLite+stripPlot = toVegaLite+    [ dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]+    , mark Tick []+    , encoding (position X [ PName "plx", PmType Quantitative ] [])+    ]++-- $background-note+-- The default background color for the visualization, at least in the+-- Vega-Embed PNG and SVG output, is white (in Vega-Lite version 4;+-- prior to this it was transparent). In many cases this is+-- perfectly fine, but an explicit color can be specified using the+-- 'Background' configuration option, as shown here, or with the+-- 'background' function, which is used in the choropleth examples+-- below ('choroplethLookupToGeo').++{-|++The 'configure' function allows a large number of configuration+options to be configured, each one introduced by the+'configuration' function. Here I set the color to be a light gray+(actually a very-transparent black; the 'Color' type describes the+various supported color specifications, but it is generally safe to assume+that if you can use it in HTML then you can use it here).++<<images/vl/stripplotwithbackground.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEDGD2B2AzAlgc0gLjMSAjAhtANaoBOsArvACaZSmoEAUADADRjuccsB0AjAEpIAXzbgoAW3ykidSABdkxSOIiRq+BfjqgI6iqQA28gBYKFABwDOGAPR3S+AO69UyBaYq4K1gKakcPAKfsG8cJJ2ACKUqABChkR+dqYAbn6o+HbS1iGkKemZdpradpnI+AC0+FUAbPy11fwsldq4Rn78+LzwsJWmfvjUAbwK1qmqEuqIsKTSCrqKAJ6WfvJjEyISYhKQACTW0APSZhY29naF3e6e3rzIsHaHx1lXlUYeyakAzLwAVtYEJN1KE4NRkPB0FgcAAPRYoPxGWhYSCWIxwjjLVbyACOFHwwQ8WmQ6VEWxEQA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"plx\", PmType Quantitative ]++    conf = 'configure'+             . 'configuration' ('Background' "rgba(0, 0, 0, 0.1)")++in toVegaLite+    [ dataFromUrl \"https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv\" [TSV]+    , mark Tick []+    , enc []+    , conf []+    ]+@++If you want a transparent background (as was the default with Vega-Lite 3+and earlier), you would use++@+'configuration' ('Background' "rgba(0, 0, 0, 0)")+@++-}++stripPlotWithBackground :: VegaLite+stripPlotWithBackground = toVegaLite+    [ dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]+    , mark Tick []+    , encoding (position X [ PName "plx", PmType Quantitative ] [])+    , configure (configuration (Background "rgba(0, 0, 0, 0.1)") [])+    ]+++{-|+There is nothing that forces us to use the x axis, so let's+try a vertical strip plot. To do so requires changing only+__one__ character in the specifiction, that is the first argument to+'position' is now 'Y' rather than 'X':++<<images/vl/stripploty.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CmBIdABPDgVmPIKAX0JWoqgAEi5sDLhmNk4efndkiSlZEUwVXj6Bh3H-BklLawBmEQArLnVCwkgtVSJMNTFqyDrLkswFBiJmDgYAD0KMBqa0SABHWlgNJJSJhbJBWp1Dqo1LcLmhgO1WkA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position 'Y' [ PName "plx", PmType Quantitative ]++in toVegaLite+    [ dataFromUrl \"https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv\" [TSV]+    , mark Tick []+    , enc []+    ]+@+-}+stripPlotY :: VegaLite+stripPlotY = toVegaLite+    [ dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" [TSV]+    , mark Tick []+    , encoding (position Y [ PName "plx", PmType Quantitative ] [])+    ]+++{-|+Since we are going to be using the same data source, let's define it here:++@+gaiaData =+  let addFormat n = (n, 'FoNumber')+      cols = [ \"RA_ICRS\", \"DE_ICRS\", \"Gmag\", \"plx\", \"e_plx\" ]+      opts = [ 'Parse' (map addFormat cols) ]++  in dataFromUrl "https:\/\/raw.githubusercontent.com\/DougBurke\/hvega\/master\/hvega\/data\/gaia-aa-616-a10-table1a.no-header.tsv" opts+@++The list argument to 'dataFromUrl' allows for some customisation of+the input data.  Previously I used @['TSV']@ to specify the data is in+tab-separated format, but it isn't actually needed here (since the+file name ends in \".tsv\"). However, I have now explicitly defined how+to parse the numeric columns using 'Parse': this is because the columns+are read in as strings for this file by default, which actually doesn't+cause any problems in most cases, but did cause me significant problems+at one point during the development of the tutorial! There is limited+to no feedback from the visualizer for cases like this (perhaps I should+have used the Javascript console), and I only realised the problem thanks+to the @Data Viewer@ tab in the+<https://vega.github.io/editor/#/ Vega Editor>+(after a+<https://twitter.com/pkgw/status/1167127390880968707 suggestion from a colleague>).++Data can also be defined algorithmically - using 'dataSequence' and+'dataSequenceAs' - or inline - with 'dataFromColumns' or+'dataFromRows' - or directly from JSON (as a 'Data.Aeson.Value') using+'dataFromJson'.++An example showing 'dataFromColumns' is the 'skyPlotWithGraticules' plot,+but let's not peak ahead!++-}++gaiaData :: Data+gaiaData =+  let addFormat n = (n, FoNumber)+      cols = [ "RA_ICRS", "DE_ICRS", "Gmag", "plx", "e_plx" ]+      opts = [ Parse (map addFormat cols) ]++  in dataFromUrl "https://raw.githubusercontent.com/DougBurke/hvega/master/hvega/data/gaia-aa-616-a10-table1a.no-header.tsv" opts+++{-|++One question would be how the parallaxes vary by cluster: as parallax is measuring distance,+then are the clusters similar distances away from us, or is there a range of values? A+first look is to use another \"channel\" to represent (i.e. encode) the cluster:++<<images/vl/stripplotwithcolor.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CipiqA4ERWrCWqgAcTgxZjVaaBklQubayAAlAEEAfQBJAGFhgGUunr74AZaaDgYAD0Xe-qK1yH0AUSnZhbRIbt2V-ZbIBXGN7Yur5chBiABfQe+v-cgACRcbAZODMNicHj8dzJCRSWQiTAqXjA0EOGH+BiSSzWAAsIgAVlx1KsoFpVERMGpOmgajRVAxytVICVMAoGERmNMGPIXIUMABPDgKLoqaBU2BMT63KDPSgfUpsjnMJ6k4qQdBCkUXACOtFgGkkpEwtjV1EgsE2mC4zKw6ASzAACghJQxLWAABROACUkF+1H90sIkFUalZNMo30+QA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"plx\", PmType Quantitative, 'PAxis' [ 'AxTitle' \"Parallax (mas)\" ] ]+            . 'color' [ 'MName' \"Cluster\", MmType 'Nominal' ]++in toVegaLite+    [ gaiaData+    , mark Tick []+    , enc []+    ]+@++Now each tick mark is colored by the cluster, and a legend is automatically+added to indicate this mapping. Fortunately the number of clusters in the+sample is small enough to make this readable! The 'color' function has+added this mapping, just by giving the column to use (with 'MName') and+its type ('MmType'). The constructors generally begin with @P@ for+position and @M@ for mark, and as we'll see there are other property+types such as facet and text.++Vega-Lite supports several data types, represented+by the 'Measurement' type. We have already seen 'Quantitative', which+is used for numeric data, and here we use 'Nominal' for the clusters,+since they have no obvious ordering.++The labelling for the X axis has been tweaked using 'PAxis', in this+case the default value for the label (the column name) has been+over-ridden by an explicit value.++-}++stripPlotWithColor :: VegaLite+stripPlotWithColor =+  let enc = encoding+            . position X [ PName "plx", PmType Quantitative, PAxis [ AxTitle "Parallax (mas)" ] ]+            . color [ MName "Cluster", MmType Nominal ]++  in toVegaLite+     [ gaiaData+     , mark Tick []+     , enc []+     ]+++-- $stripplot-mmtype+-- It is instructive to see what happens if we change the mark type for+-- the color encoding from 'Nominal' to 'Ordinal'.++{-|++<<images/vl/stripplotwithcolorordinal.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CipiqA4ERWrCWqgAcTgxZjVaaBklQubayAAlAEEAfQBJAGFhgGUunr74AZaaDgYAD0Xe-qK1yH0AUSnZhbRIbt2V-ZbIBXGN7Yur5chBiABfQe+v-cgACRcbAZODMNicHj8dzJCRSWQiTAqXjA0EOGH+BiSSzWAAsIgAVlx1KsoFpVERMGpOmgajRVAxytVICVMAoGERmNMGPIXIUMABPDgKZjlSlqWBMT63KDPSgfUpsjnMJ6k4qQdBCkUXACOtFgGkkpEwtjV1EgsE2mC4zKw6ASzAACghJQxLWAABROACUkF+1H90sIkFUalZNMo30+QA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"plx\", PmType Quantitative, PAxis [ AxTitle \"Parallax (mas)\" ] ]+            . color [ MName \"Cluster\", MmType 'Ordinal' ]++in toVegaLite+    [ gaiaData+    , mark Tick []+    , enc []+    ]+@++As can be seen, the choice of color scale has changed to one more+appropriate for an ordered set of values.+-}+stripPlotWithColorOrdinal :: VegaLite+stripPlotWithColorOrdinal =+  let enc = encoding+            . position X [ PName "plx", PmType Quantitative, PAxis [ AxTitle "Parallax (mas)" ] ]+            . color [ MName "Cluster", MmType Ordinal ]++  in toVegaLite+     [ gaiaData+     , mark Tick []+     , enc []+     ]++-- $add-axis+-- While the strip plot shows the range of parallaxes, it is hard to+-- make out the distribution of values, since the ticks overlap. Even+-- changing the opacity of the ticks - by adding an encoding channel+-- like @'opacity' [ 'MNumber' 0.6 ]@, or by setting the 'MOpacity'+-- property of the 'mark' - only helps so much. Adding a second+-- axis is easy to do, so let's see how the parallax distribution+-- varies with cluster membership.+++{-|++The 'stripPlotWithColor' visualization can be changed to show two+variables just by adding a second 'position' declaration, which+shows that the 7 milli-arcsecond range is rather crowded:++<<images/vl/parallaxbreakdown.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAXAlgY2QGnCgBNZ1ZUxQIJIBXeAGwsgAt10AHAZxQHpf4sAO4A6AOaZ0LWgCNaXAKbxsAewB26BRpGrovACIraYgEL1EC3iwBuCsbF5wum+Fdv3eJMr3uZYAWlgAgDYARmDA0IAGfzIZBgVQ2BE1FX8WBVgiJRF0LmtIAmooADMVeDh0CipiqA4ERWrCWqgAcTgxZjVaaBklQubayAAlAEEAfQBJAGFhgGUunr74AZaaDgYAD0Xe-qK1yH0AUSnZhbRIbt2V-ZbIBXGN7Yur5chBiABfQe+v-cgACRcbAZODMNicHj8dzJCRSWQiTAqXjA0EOGH+BiSSzWAAsIgAVlx1KsoFpVERMGpOmgajRVAxytVICVMAoGERmNMGPIXIUMABPDgKLoqaBU2BMT63KDPSgfUpsjnMJ6k4qQdBCkUXACOtFgGkkpEwtjV1EgsE2mC4zKw6ASzAACghJQxLWAABROACUkF+1Glg0gAuZrPZnIu3N5e0FwtF4rUkr9hED9PUrJplG+nyAA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"plx\", PmType Quantitative, PAxis [ AxTitle \"Parallax (mas)\" ] ]+            . position Y [ PName \"Cluster\", PmType Nominal ]+            . color [ MName \"Cluster\", MmType Nominal ]++in toVegaLite+    [ gaiaData+    , mark Tick []+    , enc []+    ]+@++I have left the color-encoding in, as it makes it easier to compare to+'stripPlotWithColor', even though it replicates the information provided+by the position of the mark on the Y axis. The 'yHistogram' example+below shows how the legend can be removed from a visualization.++-}++parallaxBreakdown :: VegaLite+parallaxBreakdown =+  let enc = encoding+            . position X [ PName "plx", PmType Quantitative, PAxis [ AxTitle "Parallax (mas)" ] ]+            . position Y [ PName "Cluster", PmType Nominal ]+            . color [ MName "Cluster", MmType Nominal ]++  in toVegaLite+     [ gaiaData+     , mark Tick []+     , enc []+     ]+++-- $histogram+-- We can also \"create\" data to be plotted, by aggregating data. In this+-- case we can create a histogram showing the number of stars with the+-- same parallax value (well, a range of parallaxes).++{-|++Since sensible (hopefully) defaults are provided for unspecified settings, it+is relatively easy to write generic representations of a particular+visualization. The following function expands upon the previous+specifications by:++ * taking a field name, rather than hard coding it;++ * the use of @'PBin' []@ to ask for the x-axis values to be binned;++ * the addition of a second axis ('Y') which is used for the+   aggregated value ('Count', which means that no column has+   to be specified with @PName@);++ * and the change from 'Tick' to 'Bar' for the 'mark'.++Note that we did not have to specify how we wanted the histogram+calculation to proceed - e.g. the number of bins, the bin widths,+or edges - although we could have added this, by using a non-empty+list of 'BinProperty' values with 'PBin', if the defaults are not+sufficient.++@+simpleHistogram :: T.Text -> VegaLite+simpleHistogram field =+  let enc = encoding+              . position X [ PName field, PmType Quantitative, 'PBin' [] ]+              . position Y [ 'PAggregate' 'Count', PmType Quantitative ]++  in toVegaLite+       [ gaiaData+       , mark 'Bar' []+       , enc []+       ]+@++-}++simpleHistogram :: T.Text -> VegaLite+simpleHistogram field =+  let enc = encoding+              . position X [ PName field, PmType Quantitative, PBin [] ]+              . position Y [ PAggregate Count, PmType Quantitative ]++  in toVegaLite+     [ gaiaData+     , mark Bar []+     , enc []+     ]++{-|++With 'simpleHistogram' it becomes easy to get a histogram of the parallax+values:++<<images/vl/parallaxhistogram.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMgpKKjYEeUrC6qgAcTgRRlVqaHQFAqbKSAAlAEEAfQBJAGFBgGUOrp74Pv6oNjoAD3nu3twVqD0AUQnpubRITu2l3ZXIOVG1zbOLxchGiABfRs+P68gAEg4inScEYLHYXF4biS4kk0iEYmU3EBwPsUL8dAkFisABYhAArDhqZa3VQqfBiVTtNBVKiPciQIpiOR0fCMB44DAUshEeDUOTYKBEACebDkjAAjtRYOoJMQxDZIO9rlQhZVILARCJ4LZiGKzipqOoOZBhaKJVKZSQiPKxd8wEq8JAVKpGVTyJ93kA Open this visualization in the Vega Editor>++@parallaxHistogram = 'simpleHistogram' \"plx\"@++We can see that although parallaxes around 20 to 25 milli-arcseconds+dominated the earlier visualizations, such as 'stripPlotWithColor',+__most__ of the stars have a much-smalled parallax, with values+in the range 5 to 10.++-}++-- TODO XXX explain parallax++parallaxHistogram :: VegaLite+parallaxHistogram = simpleHistogram "plx"++{-|++A different column (or field) of the input data can be viewed,+just by changing the name in the specification:++<<images/vl/gmaghistogram.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMgpKKjYEeUrC6qgAcTgRRlVqaHQFAqbKSAAlAEEAfQBJAGFBgGUOrp74Pv6oNjoAD3nu3twVqD0AUQnpubRITu2l3ZXIOVG1zbOLxchGiABfRs+P68gAEg4inScEYLHYXF4biS4kk0iEYmU3EBwPsUL8dAkFisABYhAArDhqZa3VQqfBiVTtNBVKiPciQIpiOR0fCMVqwdrYDAUshEeDUORcyBEACebDkjAAjtRYOoJMQxDZIO9rlQRZVIByRPBbMQJWcVNR1DgoKLxVKZXKSERFRLvmAVXhICpVIyqeRPu8gA Open this visualization in the Vega Editor>++@gmagHistogram = simpleHistogram \"Gmag\"@++Here we can see that the number of stars with a given magnitude+rises up until a value of around 18, and then drops off.++-}++-- TODO XXX explain magnitudes++gmagHistogram :: VegaLite+gmagHistogram = simpleHistogram "Gmag"++++-- $ylog-histogram+-- In the case of 'parallaxHistogram', the data is __dominated__ by+-- stars with small parallaxes. Changing the scale of the+-- Y axis to use a logarithmic, rather than linear, scale /might/+-- provide more information:++{-|++<<images/vl/yloghistogram.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZjCQDOK5A9pbDZIuaQJ6T5QAZvAA2Ijs24A7ROwGQUPAA7tMkAEYVIAX0IRIAE1IpSNUBH0BXcuLWoUS+ugD0z7gHcAdIngpol9Ut6WHIAY2YpFFhIz3DiZwARZktEACFrNmdoADdYRFJnMkYQrNz85yMTZ3z4UgBaUnqANgBGJoaWnDqTdRFYFtJPKWY6uFIDEM8Uemz+In1BSTI0THMLfSUKYLN59agAcTJEDilLYnUQub2LSAAlAEEAfQBJAGFbgGUTs4vyK+uoEoRAAPb7nS56AGQBIAURe7y+alO4L+kOukFgjyBoKRP0uuwg2l2RMJkMgABJ6KE4GQOPZHC5nGVBj4-AFPPBmM4qTSCsy6iJfLAmQAWTwAK3oEX+Cl8fQ4+1ItTAAAUKKQxKRgbB6DLouEDPAZDt1pAcbQCUJ4LARAYONj-qb1EaaExLLA0TdFCoOABHSykSK+YzwXKOm5a+C61aylDytRq7ia4FgAAURQAlDpiZ7IHxVpaGKENapaAplKXICJmMddIXSIguHljJXwpZIuH9N7K-7Ayhg-2w8SiHX9OEpMJjqsidogA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName "plx", PmType Quantitative, PBin [], PAxis [ AxTitle "Parallax (mas)" ] ]+            . position Y [ PAggregate Count, PmType Quantitative, 'PScale' [ 'SType' 'ScLog' ] ]++in toVegaLite+   [ gaiaData+   , mark Bar [ 'MFill' "orange", 'MStroke' "gray" ]+   , enc []+   , 'height' 300+   , 'title' "Gaia Parallaxes" []+   ]+@++There are four new changes to the visualization created by 'simpleHistogram' (since 'PAxis'+has been used above):++ 1. an explicit choice of scaling for the Y channel (using 'PScale');++ 2. the fill ('MFill') and edge ('MStroke') colors of the histogram bars are different;++ 3. the height of the overall visualization has been increased;++ 4. and a title has been added.++If you view this in the Vega Editor you will see the following warning:++@+A log scale is used to encode bar's y. This can be misleading as the height of the bar can be arbitrary based on the scale domain. You may want to use point mark instead.+@++-}+ylogHistogram :: VegaLite+ylogHistogram =+  let enc = encoding+              . position X [ PName "plx", PmType Quantitative, PBin [], PAxis [ AxTitle "Parallax (mas)" ] ]+              . position Y [ PAggregate Count, PmType Quantitative, PScale [ SType ScLog ] ]++  in toVegaLite+     [ gaiaData+     , mark Bar [ MFill "orange", MStroke "gray" ]+     , enc []+     , height 300+     , title "Gaia Parallaxes" []+     ]+++{-|++A color encoding can also be added. When used with the 'Tick' mark -+'stripPlotWithColor' - the result was that each tick mark was colored+by the \"Cluster\" field, but for the 'Bar' mark the result is that+the bars are stacked together. I have also taken the opportunity to+widen the plot ('width'); define the binning scheme used, with @'Step'+1@; and configure the location of the x axis tick marks, using+'AxValues'.++<<images/vl/gmaghistogramwithcolor.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQBGFkhEkAJqSqTaBMwK7kAbGjBQoADgGd0AemnlSAdwB0ieCmi9avCbHIBjAPYA7FLBNLDxaQBEDvRACF+lWNOgA3WIlLSyE0+Runt7SbBzS3vCkALSkMQBsAIzxsYk40Ry0ArCJpEpGBtFwpCy6SigS7oxEzABmBuRkaJjcPMxiFDpcNW1QAOJkiMJGvMS0utW9PJAASgCCAPoAkgDCMwDKw6Pj5JNTUGICAB5bYxNM+5DWAKLLa5uYkCNnuxdTkLALhyePzzuQPQgAF8eiDgRdIAp4Cx1DQACx4CEAEgkejgZGEqHEUlkwTyqnUmiU8AM0lR6J8eOiAjUrnccKUACsJMY9h8jIYWPAjEMWj1IIYBA0uJBavBYAIWMIVgJtAFGFAUABPMSwYYGYjc0hCIFvKA-MCtNqi8WS4QDUhDPXMWjckX+WBiGiJXWAxUqtWPACOvFIJjU7Hgnj2xtIR3gEhF7m1vFgkcwAG0CGAAKz4MBpdOJNNgABMOAAumCeK7jUqRZbEOQvOxPVBDLwTArIMrVcIfX6UAGu8Hi6X68YxbzDSCgUA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"Gmag\", PmType Quantitative, binning, axis ]+            . position Y [ PAggregate Count, PmType Quantitative ]+            . color [ MName \"Cluster\", MmType Nominal ]++    binning = PBin [ 'Step' 1 ]+    axis = PAxis [ 'AxValues' ('Numbers' [ 0, 5 .. 20 ]) ]++in toVegaLite+   [ gaiaData+   , mark Bar []+   , enc []+   , height 300+   , 'width' 400+   ]+@++Note that @hvega@ will allow you to combine a 'color' encoding with a 'ScLog'+scale, even though a Vega-Lite viewer will not display the+resulting Vega-Lite specification, saying++@Cannot stack non-linear scale (log)@++-}+gmagHistogramWithColor :: VegaLite+gmagHistogramWithColor =+  let enc = encoding+              . position X [ PName "Gmag", PmType Quantitative, binning, axis ]+              . position Y [ PAggregate Count, PmType Quantitative ]+              . color [ MName "Cluster", MmType Nominal ]++      binning = PBin [ Step 1 ]+      axis = PAxis [ AxValues (Numbers [ 0, 5 .. 20 ]) ]++  in toVegaLite+     [ gaiaData+     , mark Bar []+     , enc []+     , height 300+     , width 400+     ]++{-|++Notice how we never needed to state explicitly that we wished our bars+to be stacked. This was reasoned directly by Vega-Lite based on the+combination of bar marks and color channel encoding. If we were to+change just the mark function from 'Bar' to 'Line', Vega-Lite produces an+unstacked series of lines, which makes sense because unlike bars,+lines do not occlude one another to the same extent.++<<images/vl/gmaglinewithcolor.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQA28AdrJIRJACakqk2gRsBXcrRowUKAA4BndAHpZ5UgHcAdIngpoAgEYCpscgGMA9gxSwzKk8VkARYwMQAhIZVizoAN1iJSsslLm5B7evrKc3LK+8KQAtKRxAGwAjInxyTix3Nq0sMmkKgzGsXCk7AYqKFKeLERsAGbG5GRomHz8bBIU+rx1HVAA4mSIogwCxNoGtf38kABKAIIA+gCSAMJzAMqj45Pk0zNQErQAHjsTU6yHkLYAoqsb25iQYxf7VzOQsEvHZ8+ve0gfQgAF8+mDQVdIEp4OxNDQACx4KEAEikhjgZFEqEkMnkoQK6k0OhU8GMsnRmL8BNi9HMsk8CJUACspKYDl8GCZ2IwRm0+pATLQmrxIPV4LBaOxRGtaHogiwoCgAJ4SZj-YzERikEQgj5QP5gdodMUSqWiIakEb6tjaRiiwKwCQ0ZJ64FK1XqqAARwEpDMGi48G8BxNpBO8Ckos8OoEsCjmAA2gQwABWfBgDIZ5LpsAAJhwAF0Ifw3SblaKrYhyD4uF7BQ4zIrICq1aJff6UIGuyGS2WoCYGOK+UawSCgA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"Gmag\", PmType Quantitative, binning, axis ]+            . position Y [ PAggregate Count, PmType Quantitative ]+            . color [ MName \"Cluster\", MmType Nominal ]++    binning = PBin [ Step 1 ]+    axis = PAxis [ AxValues (Numbers [ 0, 5 .. 20 ]) ]++in toVegaLite+   [ gaiaData+   , mark 'Line' []+   , enc []+   , height 300+   , width 400+   ]+@++-}++gmagLineWithColor :: VegaLite+gmagLineWithColor =+  let enc = encoding+              . position X [ PName "Gmag", PmType Quantitative, binning, axis ]+              . position Y [ PAggregate Count, PmType Quantitative ]+              . color [ MName "Cluster", MmType Nominal ]++      binning = PBin [ Step 1 ]+      axis = PAxis [ AxValues (Numbers [ 0, 5 .. 20 ]) ]++  in toVegaLite+     [ gaiaData+     , mark Line []+     , enc []+     , height 300+     , width 400+     ]+++-- $histogramChoice+-- The previous histogram visualizations have taken advantage of Vega-Lite's+-- ability to bin up ('Count') a field, but there are a number of aggregation+-- properties (as defined by the 'Operation' type). For example, there+-- are a number of measures of the \"spread\" of a population, such as+-- the sample standard deviation ('Stdev').+--+-- You can also syntehsize new data based on existing data, with the+-- 'transform' operation. Unlike the 'encoding' function, the order+-- of the arguments to 'transform' do matter, as they control the+-- data flow (e.g. you can not filter a data set if you have not+-- created the field to be filtered).++{-|+The aim for this visualization is to show the spread in the @Gmag@ field+for each cluster, so we now swap the axis on which the aggregate is+being applied (so that the cluster names appear on the y axis),+and hide the legend that is applied (using @'MLegend' []@) since+we can read off the color mapping from the y axis.++<<images/vl/yhistogram.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuMxIHsAOsDGAlgC4CeqYADAHQBsANFKdgKbmQBGCkAvneFABNYRWOVAQIkAK7wANmwAWRItgDOKAPQb4sAO5UA5sQVT2U1c3h5MAOyLM7Va9A0ARTFIMAhGYmYaFADdmA1gNOFV7eADg0I0hEQ1QglgAWlg0mgBGGnSsilSRdllmLNgqG0xUhWZYAUsqIlVAyD4JKAAzTHg4IjF+dshceAt+9sGAcTgDNhspaHZLVoHxyAAlAEEAfQBJAGE1gGVZ+cX4ZfGJIdkADxOFpbbLqFcAUV2D47RIOYfzp8ukGYW2wt3uZ0gKwg3BWMOhT0gABJVHganBFMo1JoNLFykYiCZ2FQCJgNCi0WFcalZMR-IEACxUABWqlsFygDmsAgINhmaHEV2ssm6YkgHQIzFkAjYe1k5iirUYJBYs0w0B5sHkDEgJQMDmlaDmslkvBWkDu-LFEqlbCmsBm2vtBngIWErG+kXqLW1THdUAAjlJYHZiMICMEeACoGRLeLJQaoLL5Y8lSrvpV1TZNTx+KbJNYbOK+egYdwgA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"Gmag\", PmType Quantitative, PAggregate 'Stdev' ]+            . position Y [ PName \"Cluster\", PmType Nominal ]+            . color [ MName \"Cluster\", MmType Nominal, 'MLegend' [] ]++in toVegaLite+   [ gaiaData+   , mark Bar [ 'MOpacity' 0.6 ]+   , enc []+   ]+@++The bar opacity is reduced slightly with 'MOpacity 0.6' so that the+x-axis grid lines are visible. An alternative would be to change the+'AxZIndex' value for the 'X' encoding so that it is drawn on top of+the bars.++-}++yHistogram :: VegaLite+yHistogram =+  let enc = encoding+              . position X [ PName "Gmag", PmType Quantitative, PAggregate Stdev ]+              . position Y [ PName "Cluster", PmType Nominal ]+              . color [ MName "Cluster", MmType Nominal, MLegend [] ]++  in toVegaLite+     [ gaiaData+     , mark Bar [ MOpacity 0.6 ]+     , enc []+     ]++++{-|++Aggregation can happen in the position channel - as we've seen with+the 'PAggregate' option - or as a 'transform', where we create+new data to replace or augment the existing data. In the following+example I use the 'aggregate' transform to calculate the number of+rows in the original dataset per cluster with the+'Count' operation. This effectively replaces+the data, and creates a new one with the fields @\"Cluster\"@ and+@\"count\"@.++The other two major new items in this visualization are that the+X axis has been ordered to match the Y axis (using 'ByChannel' and+'PSort' in the 'position' encoding), and I have specified my own SVG+definition for the symbols with 'SymPath' and 'MShape'.++<<images/vl/starcount.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxhIBzWdAVwAcAjATz0MgGEAba5aAU1kgBdADRR45Sr3Lw+LAmXS0WkAMY1E0SKMjxkytdQ2QAvoOPERxSFniwA1i1AkoPKnd4B1AJYATaAAsWAEZhYghIZC8AL15ggAY40OcIuHR3ZXoOeBUHJJJIVC8ODmVGXmL0AHctMJd-eFpY-EgAWTBEgFogsAAZdoA6ACYAZmEOuKHh3rAQ8cnpieGADmEJwe6+iYA2QdX+gE4AFgW9w-3puZ29o4vFlbWNsC6xtam+uZGX+c2x7qia5LQRiNZS0dBeIzEYx5SA+GTwRy1SDUWAlZr+aDQWjIXAAelxCEq-XIXgC1Ho3H4ag0vA0-TUWFxABEaOQAEIo9y4-wANyk8FxNh4-G5fOkuLh0AF0i88A68DlWyCW3lQTiHSlmV4QXg-UQ6A6-l48B8-H60GQPIB+Qw2BkiOc4VotmQTVItWSAHEbORlIhqFh6PxrY6oAAlACCAH0AJJsMMAZT9AaDAjyocgtA4AA9k4Hg+nHZAmQBRWPxpPNf35tMe-K8KNZ3NVlPBuvmZwdsDQqwAEmQKiNNmUGKxOPxYt1JLJ9H6XnQuIHQ4Fk46HFJvFxPMO-QAVsh0IhrZBaWofBDffgnPlm6QCl5yj5lJxuHw0y5MJoryfEGeL6UTG0IEQSrdAsAheASh7ZJmCvOt70ffR1E0QtwmAt1IAAR2oJBoFJGQvD5EN8ngbMvD0b88OgDgMIAOVbWAwHQVAwB4F0TFqLtoKgalCkvUhzGMIA Open this visualization in the Vega Editor>++@+let trans = 'transform'+            . 'aggregate' [ 'opAs' 'Count' \"\" \"count\" ]+                        [ \"Cluster\" ]++    enc = encoding+          . position X [ PName \"Cluster\"+                       , PmType Nominal+                       , 'PSort' [ 'ByChannel' 'ChY' ]+                       ]+          . position Y [ PName \"count\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"Number of stars\" ]+                       ]++    star = 'SymPath' \"M 0,-1 L 0.23,-0.23 L 1,-0.23 L 0.38,0.21 L 0.62,0.94 L 0,0.49 L -0.62,0.94 L -0.38,0.21 L -1,-0.23 L -0.23,-0.23 L 0,-1 z\"++in toVegaLite [ gaiaData+              , trans []+              , enc []+              , mark 'Point' [ 'MShape' star+                           , MStroke \"black\"+                           , 'MStrokeWidth' 1+                           , MFill \"yellow\"+                           , 'MSize' 100+                           ]+              ]+@++Notes:++- the star design is based on a+<https://upload.wikimedia.org/wikipedia/commons/a/a5/Star_with_eyes.svg Wikipedia design>,+after some hacking and downsizing (such as losing the cute eyes);++- when using 'Count' with 'opAs', the first 'FieldName' argument is ignored,+so I set it to the empty string @\"\"@ (it's be great if the API were such+we didn't have to write dummy arguments, but at present @hvega@+doesn't provide this level of safety);++- although the order of operations of 'transform' is important, here+  I only have one (the 'aggregate' call);++- and the order of the arguments to 'toVegaLite' does not matter (so you+  can have the 'transform' appear before 'encoding' or after it).++-}++starCount :: VegaLite+starCount =+  let trans = transform+              . aggregate [ opAs Count "" "count" ]+                          [ "Cluster" ]++      enc = encoding+            . position X [ PName "Cluster"+                         , PmType Nominal+                         , PSort [ ByChannel ChY ]+                         ]+            . position Y [ PName "count"+                         , PmType Quantitative+                         , PAxis [ AxTitle "Number of stars" ]+                         ]++      -- based on https://upload.wikimedia.org/wikipedia/commons/a/a5/Star_with_eyes.svg+      star = SymPath "M 0,-1 L 0.23,-0.23 L 1,-0.23 L 0.38,0.21 L 0.62,0.94 L 0,0.49 L -0.62,0.94 L -0.38,0.21 L -1,-0.23 L -0.23,-0.23 L 0,-1 z"++  in toVegaLite [ gaiaData+                , trans []+                , enc []+                , mark Point [ MShape star+                             , MStroke "black"+                             , MStrokeWidth 1+                             , MFill "yellow"+                             , MSize 100+                             ]+                ]+++{-|++I've shown that the number of stars per cluster increases when+ordered by increasing count of the number of stars per cluster,+which is perhaps not the most informative visualization. How about+if I ask if there's a correlation between number of stars and+distance to the cluster (under the assumption that objects further+away can be harder to detect, so there /might/ be some form of+correlation)?++To do this, I tweak 'starCount' so that we also calculate the+parallax to each cluster in the 'transform' - in this case taking+the median value of the distribution thanks to the 'Median' operation - and+then using this new field to order the X axis with 'ByFieldOp'. Since+parallax is inversely correlated with distance we use the+'Descending' option to ensure the clusters are drawn from near to+far. We can see that there is no obvious relation with distance.++<<images/vl/starcount2.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxQSTIBzWdAVwAcAjATz0MgGEAbW5aAU1iQAugBpi5SPErV+leALZFy5YJHT02kAMZ1E0SKKjxkWxLSyNBkAL7iVJNRq1Z+AEwCWSQ8dP5I9FwAHgD6rm4+kKge-FwR-oFBthIkwik2xGLEkFjwsADWbGQUfDT5-ADqHm7QABZsAIz2JR4AXvyNAAydzRCQpejlWoxc8NqFvVDRXFxazLFc6ADuhin9tfD0Hf4AsmA9ALQNYAAy+wB0AEwAzKIHnVfXp2BN94-PD9cAHKIPl8dnB4ANkuv3OAE4ACwfMGQ8HPN4gsFQhGfH5-AFgI53P5PM5vG4496Au7HVqrSTQZhbLT0dAefSQYh2bJuBTwIprWiwWb+WrQaD0ZC4AD0IoQS3OlA8dVojF4gl0+n4+nOuiwIoAInRKAAhbnlEW1ABucngItyfEERtN8hFbOg5vkXgO8HgByBDSBroanQOjpG-Aa8HOiHQB1q-HgbkE52gyGNFIoGGwCk5DgCeWQ21IKUkAHFcpQzBYrEJJpIAEoAQRCAEkOJWAMolyzWCsURKtstJjOagCi9cbLf85jb5bzFH4IS7o9L1knGXIS7ALL6ABJkNpI7ktPzBcKxbaQ9LZYxzh50CKtzvzceDlwZfwRcbIecAFbIdCIJOQFW6TxEGLfBij6JIQMnKIYjiLRuF4AQJwzL9YAMED1E0fxciSIwoNieIoESMJ3EiTAYyEfwYy3FVAOLNcVBgakc0gMMsAZeBZnSSZIFYCCM2iPDu3bSCqRpfwAEdaCQaAZQUDxTV7Ch4CCDw-FIGAZS4JiADl51gMB0FQMA+CzZJl2ZZodG-aJgNIDIbCAA Open this visualization in the Vega Editor>++@+let trans = transform+            . aggregate [ opAs Count \"\" \"count\"+                        , opAs 'Median' \"plx\" \"plx_med\"+                        ]+                        [ \"Cluster\" ]++    enc = encoding+          . position X [ PName \"Cluster\"+                       , PSort [ 'ByFieldOp' \"plx_med\" 'Max'+                               , 'Descending'+                               ]+                       ]+          . position Y [ PName \"count\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"Number of stars\" ]+                       ]++    star = SymPath \"M 0,-1 L 0.23,-0.23 L 1,-0.23 L 0.38,0.21 L 0.62,0.94 L 0,0.49 L -0.62,0.94 L -0.38,0.21 L -1,-0.23 L -0.23,-0.23 L 0,-1 z\"++in toVegaLite [ gaiaData+              , trans []+              , enc []+              , mark Point [ MShape star+                           , MStroke \"black\"+                           , MStrokeWidth 1+                           , MFill \"yellow\"+                           , MSize 100+                           ]+              ]+@++Notes:++- I find the \"Data Viewer\" section of the+<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxQSTIBzWdAVwAcAjATz0MgGEAbW5aAU1iQAugBpi5SPErV+leALZFy5YJHT02kAMZ1E0SKKjxkWxLSyNBkAL7iVJNRq1Z+AEwCWSQ8dP5I9FwAHgD6rm4+kKge-FwR-oFBthIkwik2xGLEkFjwsADWbGQUfDT5-ADqHm7QABZsAIz2JR4AXvyNAAydzRCQpejlWoxc8NqFvVDRXFxazLFc6ADuhin9tfD0Hf4AsmA9ALQNYAAy+wB0AEwAzKIHnVfXp2BN94-PD9cAHKIPl8dnB4ANkuv3OAE4ACwfMGQ8HPN4gsFQhGfH5-AFgI53P5PM5vG4496Au7HVqrSTQZhbLT0dAefSQYh2bJuBTwIprWiwWb+WrQaD0ZC4AD0IoQS3OlA8dVojF4gl0+n4+nOuiwIoAInRKAAhbnlEW1ABucngItyfEERtN8hFbOg5vkXgO8HgByBDSBroanQOjpG-Aa8HOiHQB1q-HgbkE52gyGNFIoGGwCk5DgCeWQ21IKUkAHFcpQzBYrEJJpIAEoAQRCAEkOJWAMolyzWCsURKtstJjOagCi9cbLf85jb5bzFH4IS7o9L1knGXIS7ALL6ABJkNpI7ktPzBcKxbaQ9LZYxzh50CKtzvzceDlwZfwRcbIecAFbIdCIJOQFW6TxEGLfBij6JIQMnKIYjiLRuF4AQJwzL9YAMED1E0fxciSIwoNieIoESMJ3EiTAYyEfwYy3FVAOLNcVBgakc0gMMsAZeBZnSSZIFYCCM2iPDu3bSCqRpfwAEdaCQaAZQUDxTV7Ch4CCDw-FIGAZS4JiADl51gMB0FQMA+CzZJl2ZZodG-aJgNIDIbCAA Vega Editor>+rather useful when creating new data columns or structures,+as you can actually see what has been created (I find Firefox works much+better than Chrome here);++- the use of 'ByFieldOp' here is a bit un-settling, as you need to+give it an aggregation-style operation to apply to the data field,+but in this case we have already done this with 'opAs' (so I pick+'Max' as we just need something that copies the value over).++We revisit this data in 'layeredCount'.++-}+++starCount2 :: VegaLite+starCount2 =+  let trans = transform+              . aggregate [ opAs Count "" "number"+                          , opAs Median "plx" "plx_med"+                          ]+                          [ "Cluster" ]++      enc = encoding+            . position X [ PName "Cluster"+                         , PmType Nominal+                         -- I think I want a ByField back+                         , PSort [ ByFieldOp "plx_med" Max+                                 , Descending+                                 ]+                         ]+            . position Y [ PName "number"+                         , PmType Quantitative+                         , PAxis [ AxTitle "Number of stars" ]+                         ]++      star = SymPath "M 0,-1 L 0.23,-0.23 L 1,-0.23 L 0.38,0.21 L 0.62,0.94 L 0,0.49 L -0.62,0.94 L -0.38,0.21 L -1,-0.23 L -0.23,-0.23 L 0,-1 z"++  in toVegaLite [ gaiaData+                , trans []+                , enc []+                , mark Point [ MShape star+                             , MStroke "black"+                             , MStrokeWidth 1+                             , MFill "yellow"+                             , MSize 100+                             ]+                ]++++{-|++Vega-Lite supports a number of data transformations, including+several \"pre-canned\" transformations, such as a+kernel-density estimator, which I will use here to+look for structure in the parallax distribution. The earlier+use of a fixed-bin histogram - 'parallaxHistogram' and 'ylogHistogram' -+showed a peak around 5 to 10 milli-arcseconds, and a secondary+one around 20 to 25 milli-arcseconds, but can we infer anything more+from the data?++I have already shown that the 'transform'+function works in a similar manner to 'encoding', in that+it is applied to one or more transformations. In this+example I use the 'density' transform - which is __new to Vega Lite 4__ -+to \"smooth\" the data without having to pre-judge the data+(although there are options to configure the density estimation).+The transform creates new fields - called \"value\" and \"density\"+by default - which can then be displayed as any other field. In this+case I switch from 'Bar' or 'Line' to use the 'Area' encoding, which+fills in the area from the value down to the axis.++<<images/vl/densityparallax.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hIATAUxQEtoBPPKABwBsAPSAXwF0AacKLeLADW9UBAiR0DeAGNqdfAAYAdAHZe4qMjjohZepABGTWSI3jI22LrIAReMgAW9AgCZuYACw8+E2g318SEEyeEg+dnNSeGgw-DELAFdYJgNHaGgGZFwAehyEAHdlAHNqR0TDROQyWBl0RGgKaGU6rBzbdETigCFkvRzHADcyYvgcgW0ageHRnJIYsdHKeABaeFWANgBGDbWtxRXY4zIt+GVEdBXHUPJYZWhkQchzCQxsGNFfC2lYas-NTSQADiAmKBkQiSwhhqzy+gIASgBBAD6AEkAMLwgDK4Mh0NgsIB31YuKhMJeAMgtgAomjMTighCyQSKYCyMjmGxGXiYXCwOwvgKIJE+JAACTIGTXARpDJZXI5GZnUrQcqGZSUdA5SXSsZKlZMahkRWeZQAK2Q9UJUAodRIlEQYPiX0gXLACUBqEoZCYJAMg3gTES+lZUH8gSgAEdEkhoNQYpRhtbAfAWJRkKIYNQmBHID9AyY2ELxCLAQp3ZAvT6-UFyFRaM8wzQAgZo7H43Gk8XS1A6ogvU73QL2EA Open this visualization in the Vega Editor>++@+let trans = transform+            . 'density' \"plx\" []++    enc = encoding+          . position X [ PName \"value\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"parallax\" ]+                       ]+          . position Y [ PName \"density\", PmType Quantitative ]++in toVegaLite+     [ gaiaData+     , mark 'Area' [ MOpacity 0.7+                 , MStroke \"black\"+                 , 'MStrokeDash' [ 2, 4 ]+                 , ]+     , trans []+     , enc []+     ]+@++The parallax distribution shows multiple peaks within the+5 to 10 milli-arcsecond range, and separate peaks at 12+and 22 milli-arcseconds.++The properties of the area mark are set here to add a black,+dashed line around the edge of the area. The 'DashStyle' configures+the pattern by giving the lengths, in pixels,+of the \"on\" and \"off" segments, so here the gaps are twice the+length of the line segments. This was done more to show that it+can be done, rather than because it aids this particular visualization!++-}++densityParallax :: VegaLite+densityParallax =+  let trans = transform+              . density "plx" []++      enc = encoding+            . position X [ PName "value"+                         , PmType Quantitative+                         , PAxis [ AxTitle "parallax" ]+                         ]+            . position Y [ PName "density", PmType Quantitative ]++  in toVegaLite+       [ gaiaData+       , mark Area [ MOpacity 0.7+                   , MStroke "black"+                   , MStrokeDash [ 2, 4 ]+                   ]+       , trans []+       , enc []+       ]+++{-|++The density estimation can be configured using 'DensityProperty'.+Here we explicitly label the new fields to create (rather than+use the defaults), and ensure the calculation is done per cluster.+This means that the data range for each cluster is used to+perform the KDE, which in this case is useful (as it ensures the+highest fidelity), but there are times when you may wish to ensure+a consistent scale for the evaluation (in which case you'd use+the 'DnExtent' option, as well as possibly 'DnSteps', to define+the grid). The final change is to switch from density estimation+to counts for the dependent axis.++<<images/vl/densityparallaxgrouped.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxQSTIBzWdAVwAcAjATz0MgGEAbW5aAU1iQAugBpi5SPGRsCkAB4BrACb9IoqMxVqxEigGM6iaDPxxa-ceQiRVKAJbRW+SPS7zIegL7FdNrPCwimzAkOj08PqOzmAADAB0AOwaMMz0ai6B-PCQXlZQyvDQOfhkFLSwXGyQABbQ0PTIuAD0zQgA7vGUjjW0jLyChsb8xvGGWM0AInSUAEIVivzNNQBu-JTwzQF8gstrG82Fxc0b9vAAtPAXAGwAjNeXt7HnxYxc-Lfw8Yjo5zXZqlg8RMK3UekgGGwRRCehsEVgyAypFhFAA4gFKNVELQsIxBGDrBQAEoAQQA+gBJDhEgDKWJxeKE+UJrnc9Nx+OZ1kgkwAopTqXSXNiOUyUTZ+GS3B5hQz8SifORFWA8sRIAASZD6f4Bap1BpNVr7L7daC9RjxezoZpanWbY3nLiOJYrAAs8QAVsh0IgCVARoZlPZEJjSuDDFxMCEIfZ+FxlNVuLwBEyoE50lj0Fhg-AqqrJDLkSzULH49UlKo-ZJ00jIABHWhIaCOIr2NZVijweT2UykGCOd7VAAKgVzXC7uW8XMgMVCJbjCZcWkrKRr1QbTZbzfbKS7Pejzegg5cHCMJlyyvzUCGJdDpB8XiAA Open this visualization in the Vega Editor>++@+let trans = transform+            . density "plx" [ 'DnAs' \"xkde\" \"ykde\"+                            , 'DnGroupBy' [ \"Cluster\" ]+                            , 'DnCounts' True+                            ]++    enc = encoding+          . position X [ PName \"xkde\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"Parallax\" ]+                       ]+          . position Y [ PName \"ykde\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"Counts\" ]+                       ]+          . color [ MName \"Cluster\"+                  , MmType Nominal+                  ]++in toVegaLite+     [ gaiaData+     , mark Area [ MOpacity 0.7 ]+     , trans []+     , enc []+     ]+@++Note how the clusters separate out in pretty cleanly, but - as+also shown in the 'pointPlot' visualization below - it is pretty+busy around 7 milli arcseconds.++The counts here (the Y axis) are __significantly larger__ than+seen than the actual count of stars, shown in 'starCount'. It+appears that the @'DnCounts' True@ option is interpreted as+<https://vega.github.io/vega-lite/docs/density.html#example-stacked-density-estimates multiplying the density values by the number of values in a group>,+which means that there is a bin-width effect. This is explored+further in the 'compareCounts' plot below.++-}++densityParallaxGrouped :: VegaLite+densityParallaxGrouped =+  let trans = transform+              . density "plx" [ DnAs "xkde" "ykde"+                              , DnGroupBy [ "Cluster" ]+                              , DnCounts True+                              ]++      enc = encoding+            . position X [ PName "xkde"+                         , PmType Quantitative+                         , PAxis [ AxTitle "Parallax" ]+                         ]+            . position Y [ PName "ykde"+                         , PmType Quantitative+                         , PAxis [ AxTitle "Counts" ]+                         ]+            . color [ MName "Cluster"+                    , MmType Nominal+                    ]++  in toVegaLite+       [ gaiaData+       , mark Area [ MOpacity 0.7 ]+       , trans []+       , enc []+       ]+++-- $intro-points+-- At this point we make a signifiant detour from the Elm Vega-Lite+-- walkthtough, and look a bit more at the 'Point' mark, rather than creating+-- small-multiple plots. Don't worry, we'll get to them later.+--+-- I apologize for the alliterative use of point here.++{-|++Here I use the 'Point' mark to display the individual+@Gmag, plx@ pairs, encoding by __both__ 'color' and 'shape.+Since the encoding uses the same field of the data (the @Cluster@+name), Vega-Lite is smart enough to only display one legend,+which contains the point shape and color used for each cluster.++Since the parallax values are bunched together at low values,+a logarithmic scale ('ScLog') is used for the y axis, along with+commands to define the actual axis domain - by turning off the+'IsNice' support and listing the minimum and maximum values+for the axis with 'SDomain'.++<<images/vl/pointplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMAWADDgNOFALYCGATgNYZQAOA9vAHZqESQAmpKpNoE7AK7kANjRgoUtAM7oA9HPKkA7gDpE8FNEEAjQdNjkAxvRawWqk8TkAReoMQAhYZVhzoAN1iJScstJRDdy8fOS4eOR94UgBaUliANgBGBLiknBieHRFYJNJVJnoYuFIOQ1UUaQ9INgFIADN6cjI0TH4BdloKAz4iDvYAcTJEcSZBYh1DGr7+yAAlAEEAfQBJAGE5gGVR8cnyaf662hEADx2JqdrDyBsAUVWN7cxIMYv9q9nYJeOz59e9yAzCAAXxmoJBtUgyngHC0NFwBCIkAAJNIjHAyOJUFJZAoQvkNFpdKp4PQ5GiMb58TERJo3B4sKoAFbSUwHKDmEwcZgjNozSAmERNPgNeCwEQccRrET6QLvKAoACetFgo3oxGYpDEwI+kGk0FIKpF9TFEqlMoClwVytVf3Vmu1ut+YGAovFkueQ1II3w1qNzwAjoJSCxNNx4F5IDr+YretcTe7xD92R09UYtbaXZx1aRmDQANoAZlUAFZfYWAEwAXV9kCV-qgQp9UCY8CMmfqWoM0eu9czkCDIZQYeHkbBRB7UBMTBNvJdoOBQA Open this visualization in the Vega Editor>++@+let enc = encoding+                    . position X [ PName \"Gmag\", PmType Quantitative ]+                    . position Y [ PName \"plx\", PmType Quantitative, PScale scaleOpts ]+                    . color cluster+                    . shape cluster++    scaleOpts = [ SType ScLog, 'SDomain' ('DNumbers' [3.5, 32]), 'SNice' ('IsNice' False) ]+    cluster = [ MName \"Cluster\", MmType Nominal ]+, +in toVegaLite [ gaiaData+              , mark Point []+              , enc []+              , width 400+              , height 400+              ]+@++We can see that each cluster appears to have a separate parallax+value (something we have seen in earlier plots, such as 'parallaxBreakdown'),+and that it doesn't really vary with Gmag. What this is telling+us is that for these star clusters, the distance to each member star+is similar, and that they are generally at different distances+from us. However, it's a bit hard to tell exactly what is going+on around 5 to 6 milli arcseconds, as the clusters overlap here.++This line of thinking leads us nicely to map making, but before we+try some cartography, I wanted to briefly provide some context for+these plots. The+<https://lco.global/spacebook/distance/parallax-and-distance-measurement/ parallax of a star>+is a measure of its distance from us, but it is an inverse relationship,+so that nearer stars have a larger parallax than those further from us.+The @Gmag@ column measures the apparent brightness of the star, with the+@G@ part indicating what+<https://www.cosmos.esa.int/web/gaia/iow_20180316 part of the spectrum>+is used (for Gaia, the @G@ band is pretty broad, covering much of+the visible spectrum), and the @mag@ part is because optical Astronomy+tends to use++ * <https://www.skyandtelescope.com/astronomy-resources/the-stellar-magnitude-system/ the logarithm of the measured flux>++ * and then subtract this from a constant++so that larger values mean fainter sources. These are also+<https://en.wikipedia.org/wiki/Apparent_magnitude apparent magnitues>,+so that they measure the flux of the star as measured at Earth,+rather than its intrinsic luminosity (often defined as an object's+<https://en.wikipedia.org/wiki/Absolute_magnitude absolute magnitude>).++We can see that the further the cluster is from us - that is, as we+move down this graph to smaller parallax values - then the+smallest stellar magnitude we can see in a cluster tends to increase,+but that there are stars up to the maximum value (20) in each cluster.+This information can be used to look at the+distribution of absolute magnitudes of stars in a cluster, which+tells us about its evolutionary state - such as is it newly formed or old -+amongst other things. However, this is straying far from the+aim of this tutorial, so lets get back to plotting things.++-}++pointPlot :: VegaLite+pointPlot =+  let enc = encoding+              . position X [ PName "Gmag", PmType Quantitative ]+              . position Y [ PName "plx", PmType Quantitative, PScale scaleOpts ]+              . shape cluster+              . color cluster++      scaleOpts = [ SType ScLog, SDomain (DNumbers [3.5, 32]), SNice (IsNice False) ]+      cluster = [ MName "Cluster", MmType Nominal ]++  in toVegaLite [ gaiaData+                , mark Point []+                , enc []+                , width 400+                , height 400+                ]++-- $intro-map+-- We have some hint that the different clusters are distinct objects+-- in space, in that they appear to be different distances from us,+-- but where does the \"cluster\" in the name \"Stellar Cluster\"+-- come from? Well, we can try plotting up the position of each star+-- on the sky - using the @RA_ICRS@ and @DE_ICRS@ fields - to find out.++{-|++The following specification should only contain one new feature - other+than sneakily switching from 'Point' to 'Circle' type for the mark - and+that is displaying the x axis (namely Right Ascension) in reverse (using+@'PSort' [ 'Descending' ]@. This is needed because Right Ascension+is measured from right to left. I like to explain it by talking about+oranges, and how we are at the center of an orange looking out at its+skin, and so have the direction reversed to if you were outside, looking+in. This may be why I don't get invited to too many parties.+You can see that we also have one cluster that straddles the+0 and 360 degrees Right Ascension meridian, which will lead to some+fun later ('clusterCenters').++<<images/vl/posplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQDG85tANrJIRJACakqk2gQOAV3JMaMFCgAOAZ3QB6eeVIB3AHSJ4KaEIBGQmbEYB7AHYpY5tbWPF5AEWNDEAIRGVY86ADdYiUvJkMhbkXr7+8ty88v7wpAC0pAkAbACMyYmpOPG8uiyppGqmxvFwpJxGaigy3mxEHABmxuRkaJgCghxSFIb89Z1QAOJkiOKmQsS6RnUDgpAASgCCAPoAkgDC8wDKYxNT5DOzUFJMAB67k9PsR5D2AKJrmzuYkOOXB9ezkLDLJ+cvb32kH6EAAvv1wWDrpAVPBONoaAAWPDQgAkMlocDI4lQ0jkinChU02j0angxnkGKxAUJ8SYWk83kRagAVjIzIdvqYbJx4KZRu1+pAbExmvxIA14LAmJxxOsmAYQmwoCgAJ5SVgA2x80hiUGfKD-MAdToSqUy8RLR7bQ6mjG6zXGri2Uh8mgAbQI2GSOAAuvgoKZ4LRHQ1dYZ9SCoOzyG0oBUMZZefzbXM1RrxABHISkcxaHjwXypjikU7wGTilBaFiWpCoMCLROmGTk0xgAAUFUQAEpIJDBJHTaq+l9JdLZS97tadgaOPaa+1nWQ3Zh3fEAJxezf+wPB0Ph2CDgaQdOOyDZ3NV3hVouzqCl8uV6tn+ywZg6qtmDtd3v9sFEI9hTMSUBWNcFQSAA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X (axOpts \"RA_ICRS\" \"Right Ascension (deg)\" ++ [ raScale, 'PSort' [ 'Descending' ] ])+            . position Y (axOpts \"DE_ICRS\" \"Declination (deg)\" ++ [ decScale ])+            . color [ MName \"Cluster\", MmType Nominal ]++    axOpts field lbl = [ PName field, PmType Quantitative, PAxis [ AxTitle lbl ]]++    scaleOpts minVal maxVal = [ SDomain (DNumbers [ minVal, maxVal ]), SNice (IsNice False) ]+    raScale = PScale (scaleOpts 0 360)+    decScale = PScale (scaleOpts (-90) 90)++in toVegaLite [ gaiaData+              , mark 'Circle' []+              , enc []+              , width 400+              , height 300+              ]+@++We can see that these clusters are indeed localised on the sky,+with <https://en.wikipedia.org/wiki/Hyades_(star_cluster) Hyades>+looking like it covers the largest area. However, we should be+careful and __not forget__ either+<https://www.youtube.com/watch?v=E9IuXEwpU7U Grover's hard work>+or+<https://www.youtube.com/watch?v=MMiKyfd6hA0 Father Ted's explanation to Father Dougal>,+since these clusters are different distances from us, which+makes size a tricky thing to measure from this plot.++There is also the fact that I have used possibly the worst+way of displaying the Right Ascension and Declination data. Although+the night sky is not the same as the Earth's surface, the issues+when trying to display the Globe on a flat surface also apply to+displaying up the sky. For this plot the distortions near the+pole are huge, although fortunately we don't have any clusters+too close to either pole.++-}++posPlot :: VegaLite+posPlot =+  let enc = encoding+              . position X (axOpts "RA_ICRS" "Right Ascension (deg)" ++ [ raScale, PSort [ Descending ] ])+              . position Y (axOpts "DE_ICRS" "Declination (deg)" ++ [ decScale ])+              . color [ MName "Cluster", MmType Nominal ]++      axOpts field lbl = [ PName field, PmType Quantitative, PAxis [ AxTitle lbl ]]++      scaleOpts minVal maxVal = [ SDomain (DNumbers [ minVal, maxVal ]), SNice (IsNice False) ]+      raScale = PScale (scaleOpts 0 360)+      decScale = PScale (scaleOpts (-90) 90)++  in toVegaLite [ gaiaData+                , mark Circle []+                , enc []+                , width 400+                , height 300+                ]+++{-|+Vega-Lite supports a large number of projections - via the+'Projection' type - which we use below to create+a similar visualization to 'posPlot'. Here I use the+'Longitude' and 'Latitude' channels, along with a+'Mercator' 'projection', to display the data.++The trick in this case is that longitude runs from -180 to 180+degrees, but the data has Right Ascension going from 0+to 360 degrees. Here we take advantage of Vega Lite's+__data transformation__ capabilities and create a new+column - which I call @longitude@ - and is defined as+\"Right Ascension - 360\" when the Right Ascension is+greater than 180, otherwise it is just set to the+Right Ascension value. The "expression" support+is essentially a sub-set of Javascript, and the @datum@+object refers to the current row. The new data column+can then be used with the 'Longitude' channel.+Thankfully the 'Latitude' channel can use the Declination values+without any conversion.++As can be seen, this flips the orientation compared to+'posPlot', and makes the center of the plot have a+longiture (or Right Ascension), of 0 degrees.++<<images/vl/skyplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxQSTJ5k8oAbdRAcwEtoBXAEwFNIAaY8pADG8WkLa140HvkgcpbLADoASgEEA+gEkAwioDKYAHxgAjAA4ADGAD8Yee2XrtewwFowAZgBs1-A8VVTV0DSAEwAF9iAF1+CEgACy5mRgToGgAWS0s4qCx4WABrGmFmWCFaHly5KXgaMgo2WFoStOgAB2RcAHpuhAB3JRZoBLYAIzZkLnKGaURoJSF0LG6AEXQ2RgAhJsKuboSANy5GeG785GlYA+PT7ocz0+Z4N3gX71NvV9NLN2h4MaVUzwJSIdBuJLwbiwJTQZCHPjhSAYbBSerheLtApTdHkQQAcXyjBKiEUY2miLxFGcIX0JLJFNyVMg7VoAA96VhybBKVSoKsAKIuUKyUlcxkYihcDSsjmihk8yVRcjKyLVfrMDgjGieACsOWIkAAJMghEl8q1oB0ur1biDhqMxkpmOhuqbzWc7W5aKx9ocMkoAFbIBi8lmwdCBrhCaAuxD1GAAT3aMjy0xE0EwkAi1S4iCWHGYTFxFCW9B5+AaglQzC4tA4JVlvMEptEqeAkHdXCwqcghzKmuY1F4UGgyd79GJOclSZTJQAjmwkLH-rHjs2KJVGHmG5WYKxKo2CqJJBzVRBp4JJCvOO3kbX6yVBcK6SPZ73F8vWFJmOvLxRM3QWhY3aBMazrXcoB0WhJiuPhR3HElliLURsyZOgGGGW8wIfSDIHoJhWGwt8xznWRP3mb81x4VV-2EBga2JSsogiIA Open this visualization in the Vega Editor>++@+let trans = transform+                . 'calculateAs'+                  "datum.RA_ICRS > 180 ? datum.RA_ICRS - 360 : datum.RA_ICRS"+                  "longitude"++    axOpts field = [ PName field, PmType Quantitative ]++    enc = encoding+            . position 'Longitude' (axOpts "longitude")+            . position 'Latitude' (axOpts \"DE_ICRS\")+            . color [ MName \"plx\"+                    , MmType Quantitative+                    , 'MScale' [ SType ScLog+                             , 'SScheme' \"viridis\" []+                             ]+                    , MLegend [ 'LTitle' "parallax" ]+                    ]+            . 'tooltip' [ 'TName' \"Cluster\", 'TmType' Nominal ]++in toVegaLite [ width 400+              , height 350+              , 'projection' [ 'PrType' 'Mercator' ]+              , gaiaData+              , trans []+              , enc []+              , mark Circle []+              ]+@++The other major change made to 'posPlot' is that the stars are now+color-encoded by the log of their parallax value+rather than cluster membership,+and the color scheme has been changed to use the \"viridis\" color+scale.+The 'LTitle' option is set for the legend (on the+'color' channel) rather than use the default (which in+this case would be @\"plx\"@).++Since parallax is a numeric value, with ordering (i.e. 'Quantitative'),+the legend has changed from a list of symbols to a gradient bar.+To account for this lost of information, I have added a 'tooltip'+encoding so that when the pointer is moved over a star its cluster+name will be displayed. This is, unfortunately,+/only/ visible in the interactive version of the visualization.++__Note that__ the tooltip behavior changed in Vega Lite 4 (or in the+code used to display the visualizations around this time), since+prior to this tooltips were on by default. Now tooltips have to be+explicitly enabled (with 'tooltip' or 'tooltips').++From this visualization we can see that the apparent size of the cluster+(if we approximate each cluster as a circle, then we can think of the radius+of the circle as a measure of size) depends on parallax, with larger+sizes having larger parallaxes. This is because the distance to a star+is inversely-dependent on its parallax, so larger parallaxes mean the+star is closer to us. However, there is no reason that the intrinsic+size - that is its actual radius - of each cluster is the same.+We can see that although the Hyades and Pleiades clusters overlap+on the sky, they have significantly-different parallaxes (as can+be seen in 'pointPlot' for example), with Hyades being the closer+of the two.++It is possible to add graticules - with the aptly-named+'graticule' function - but this requires the use of layers,+which we haven't covered yet. If you are impatient you can jump+right to 'skyPlotWithGraticules'!++If you want to see how to "create your own projection", see+'skyPlotAitoff', which uses the+<https://en.wikipedia.org/wiki/Aitoff_projection Aitoff projection>+(which is unfortunately not available to+Vega-Lite directly).++-}++skyPlot :: VegaLite+skyPlot =+  let trans = transform+                . calculateAs+                  "datum.RA_ICRS > 180 ? datum.RA_ICRS - 360 : datum.RA_ICRS"+                  "longitude"++      axOpts field = [ PName field, PmType Quantitative ]++      enc = encoding+              . position Longitude (axOpts "longitude")+              . position Latitude (axOpts "DE_ICRS")+              . color [ MName "plx"+                      , MmType Quantitative+                      , MScale [ SType ScLog+                               , SScheme "viridis" []+                               ]+                      , MLegend [ LTitle "parallax" ]+                      ]+              . tooltip [ TName "Cluster", TmType Nominal ]+              -- note: opacity doesn't really help here++  in toVegaLite [ width 350+                , height 400+                , projection [ PrType Mercator ]+                , gaiaData+                , trans []+                , enc []+                , mark Circle []+                ]+++-- $intro-choropleth+-- There are some things vega-lite can do, don't fit as well into the+-- flow of looking at astronomy data!  But having examples is helpful.+-- So we bring our eyes back to earth, and demonstrate a basic+-- "choropleth", a map - in the sense of pictures of bounded geographical+-- regions - with data for each location indicated by color.+--+-- Don't worry, we'll soon be back staring at the stars!+--+-- The choropleth examples (there's another one later on)+-- use a map of the United States as the data source, which we abstract+-- out into a helper function:+--+-- @+-- usGeoData :: T.Text -> Data+-- usGeoData f = dataFromUrl \"https:\/\/raw.githubusercontent.com\/vega\/vega\/master\/docs\/data\/us-10m.json\" ['TopojsonFeature' f]+-- @+--+-- The argument gives the \"topological\" feature in the input file to+-- display (via 'TopojsonFeature'). You can read more information on this+-- in the <https://vega.github.io/vega-lite/docs/data.html#topojson Vega-Lite documentation>.+--+-- This section was contributed by Adam Conner-Sax. Thanks!++usGeoData :: T.Text -> Data+usGeoData f = dataFromUrl "https://raw.githubusercontent.com/vega/vega/master/docs/data/us-10m.json" [TopojsonFeature f]+++{-|++Our first choropleth is based on the+<https://vega.github.io/vega-lite/examples/geo_choropleth.html Choropleth>+example from the Vega-Lite+<https://vega.github.io/vega-lite/examples/ Example Gallery>.++The key elements are:++   * Using the 'TopojsonFeature' feature for the data source (thanks to @usGeoData@).+   * Choosing the correct "feature" name in the geographic data, here @\"counties\"@+     in the argument to our @usGeoData@ helper function.+   * Performing a Vega-Lite lookup to join the data to be plotted (the unemployment rate)+     to the geographic data.  In this case, the column name in the unemployment data - @\"id\"@+     given as the first argument to 'lookup' - is the same as the column name in the+     geographic data, the third argument to 'lookup'. Those can be different.+   * Specifying a projection, that is a mapping from (longitude, latitude) to (x,y)+     coordinates. Since we are looking at data for the main-land United States of+     America we use 'AlbersUsa' (rather than looking at the whole globe, as we did+     in earlier visualizations), which lets us view the continental USA as well as Alaska and Hawaii.+   * Using the 'Geoshape' mark.++<<images/vl/choroplethlookuptogeo.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxQSTJVZ0d8zyKATeaePU4higV1gBt2kABbRoAB2S4A9FIQB3AHQBzAJbQh3AEbdkAU1gBjdImi6TCo1ikA3XUvg27DrPGSnYUxugPJPLB9yIulhifOgAnlhm0ArQyNaQnAwAvgA0SeSQANa64YIqjJDpXBCUKrp8jMjsBJAIppAAuhlgaS2QYehZ3GL5hUnJxI3FUEK6Kkoi7ADMAAyzI5AusFmCSrroyELwYrpFxJDMrOz0pbwC+MKiEtKy8Iqq6lo6+kYm0RY0jvbfzq7unm8viOAWQAFoAIyzLAKABWyGM+0yGGwLBOlF0LF4e0uRkC0HK1VSUGg4V2gmg6DE6HhiMGEDapTkBXU7AArPNFgASZAGMYuQQicSSGS2ezKNQaTQKFToKS8-kOMXwMF8NS6GwAFjhCMQSKgYmosN0BgJiLoMDJOKg8D4mn0yAAqsg2IyoGYjIwVIglCckpAjGFYH6uGUKoVLvU9iNMrzbdbgJAFcFrZAxLxQhsED69m7MqTyZcAI7cJAE1gE2yJcj01qLTTwAxZJTUQIRm0AL2x+oDxlQExOg2SQA Open this visualization in the Vega Editor>++@+let unemploymentData = dataFromUrl \"https:\/\/raw.githubusercontent.com\/vega\/vega\/master\/docs\/data\/unemployment.tsv\" []++in toVegaLite+   [ usGeoData \"counties\"+   , transform+     . 'lookup' \"id\" unemploymentData \"id\" ('LuFields' [\"rate\"])+     $ []+   , projection [PrType 'AlbersUsa']+   , encoding+     . color [ MName \"rate\", MmType Quantitative, MScale [ SScheme "purpleorange" [] ] ]+     $ []+   , mark Geoshape []+   , width 500+   , height 300+   , 'background' "azure"+   ]+@++So, we have seen how to join data between two datasets - thanks to+'lookup' - and display the unemployment rate (from one data source)+on a map (defined from another data source).++I have chosen a+<https://vega.github.io/vega/docs/schemes/index.html#diverging diverging color scheme>+for the rate, mainly just because I can, but also because I wanted to see how+the areas with high rates were clustered. I've also shown how the 'background'+function can be used (it is simpler than the 'configuration' approach+used earlier in 'stripPlotWithBackground').++Our next choropleth - 'choroplethLookupFromGeo' - will show how we can join+multiple fields across data sources, but this requires understanding how+Vega-Lite handles multiple views, which is fortunately next in our+tutorial.++-}++choroplethLookupToGeo :: VegaLite+choroplethLookupToGeo =+  let unemploymentData = dataFromUrl "https://raw.githubusercontent.com/vega/vega/master/docs/data/unemployment.tsv" []++  in toVegaLite+     [ usGeoData "counties"+     , transform+       . lookup "id" unemploymentData "id" (LuFields ["rate"])+       $ []+     , projection [PrType AlbersUsa]+     , encoding+       . color [ MName "rate", MmType Quantitative, MScale [ SScheme "purpleorange" [] ] ]+       $ []+     , mark Geoshape []+     , width 500+     , height 300+     , background "azure"+     ]+++-- $intro-layered+-- The Stacked-Histogram plot - created by 'gmagHistogramWithColor' - showed+-- the distribution of the \"Gmag\" field by cluster, but it was hard to+-- compare them. A common approach in this situation is to split up+-- the data into multiple plots -+-- the <https://en.wikipedia.org/wiki/Small_multiple small multiple>+-- approach (also known as trellis plots) - which we can easily achieve in+-- Vega Lite. It also gets us back on track with the Elm walkthrough.++{-|++Our first attempt is with the 'column' function, which tells+Vega-Lite to create a plot for each @Cluster@ field (and introduces+us to the @F@ family of 'FacetChannel' constructors).++The legend has been turned off with @'MLegend' []@, since it doesn't+add anything to this visulization (as the individual plots, labelled+by the cluster name, provide the same information).++<<images/vl/smallmultiples.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMgpKKjYEeUrC6qgAcTgRRlVqaHQFAqbKSAAlAEEAfQBJAGFBgGUOrp74Pv6oNjoAD3nu3twVqD0AUQnpubRITu2l3ZXIOVG1zbOLxchGiABfRs+P68gAEg4inScEYLHYXF4biS4kk0iEYmU3EBwPsUL8dAkFisABYhAArDhqZa3VQqfBiVTtNBVKgqOilSqQIpiOR0fCMSZ0WTOHBQIgATzYcg6ymgFNgDGwUHiIk07LQnTodHe1yoj3ITJZbMYrVg7SlkHQFLIRHg1DkBoFQsYAEdqLB1BJiGIbJAVY1IHSuqpGczWfKoJzuTs+YLhU9ReKGO7qpB+Q1+pA9SJ4LZiOGoCpqOplrGrRnIHaHUQnSXXaqBrB1mIOIyS0R4owAHILBRgZRFMAzEjwWvfSj9mOZtTMqnkT7vIA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PName \"Gmag\", PmType Quantitative, PBin [] ]+            . position Y yAxis+            . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]+            . 'column' [ 'FName' \"Cluster\", 'FmType' Nominal ]++    yAxis = [ PAggregate Count+            , PmType Quantitative+            , PAxis [ AxTitle \"Number of Stars\" ]+            ]++in toVegaLite+     [ gaiaData+     , mark Bar []+     , enc []+     ]+@++Since we have nine clusters in the sample, the overall visualization is+too wide, unless you have a very-large monitor. Can we do better?++-}++smallMultiples :: VegaLite+smallMultiples =+  let enc = encoding+              . position X [ PName "Gmag", PmType Quantitative, PBin [] ]+              . position Y yAxis+              . color [ MName "Cluster", MmType Nominal, MLegend [] ]+              . column [ FName "Cluster", FmType Nominal ]++      yAxis = [ PAggregate Count+              , PmType Quantitative+              , PAxis [ AxTitle "Number of Stars" ]+              ]++  in toVegaLite+       [ gaiaData+       , mark Bar []+       , enc []+       ]+++{-|++The number of columns used in small-multiple can be defined using the+'columns' function. However, this requires us to:++ * move the facet definition out from the encoding and into the top-level,+   with the 'facetFlow' function;++ * and define the plot as a separate specification, and apply it+   with 'specification' and 'asSpec'.++The actual syntactic changes to 'smallMultiples' are actually+fairly minor:++@+let enc = encoding+            . position X [ PName \"Gmag\", PmType Quantitative, PBin [] ]+            . position Y yAxis+            . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]++    yAxis = [ PAggregate Count+            , PmType Quantitative+            , PAxis [ AxTitle \"Number of Stars\" ]+            ]++in toVegaLite+     [ gaiaData+     , 'columns' 4+     , 'facetFlow' [ FName \"Cluster\", FmType Nominal ]+     , 'specification' ('asSpec' [ mark Bar [], enc [] ])+     ]+@++<<images/vl/smallmultiples2.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zUBRk-EIVpyY4Gga3FK6wyUlE0DYYnqqEKp1EeByBSybH4eGgDSGeD45lSUHgAE8vhMRLIobACCkoMEWFIMagmng8G97pArmgUWj6VBarB6lTINwoYR4DgsPwBYTiQcAI5YWASDgINj6SAs2aQAm-DaQPksHAGBD8BqiLASUEaqXG2XyxWIeAq43vDWwBZsCjIh3wYINAByRxwYBEmTAo0QZTV9xeGGj6qgABIKEJoiYGiRyFRaFYwuxODwmGwRNQkymjNmnHgONpdAAWJgAKwo4lBkARzTEHtQNfeWVgQn4+VhnPRmOxZmm+KJ1qgETJYgpap7ojEmTYMLQTweQA Open this visualization in the Vega Editor>++Note that Vega Lite does support a @\"facet\"@ field in its encodings,+but hvega follows Elm VegaLite and requires you to use this+<https://github.com/gicentre/elm-vegalite/issues/5#issuecomment-514501218 wrapped facet> approach.++I chose 4 columns rather than 3 here to show how "empty" plots+are encoded. You can see how a 3-column version looks in the+next plot, 'densityMultiples'.++-}++smallMultiples2 :: VegaLite+smallMultiples2 =+  let enc = encoding+              . position X [ PName "Gmag", PmType Quantitative, PBin [] ]+              . position Y yAxis+              . color [ MName "Cluster", MmType Nominal, MLegend [] ]++      yAxis = [ PAggregate Count+              , PmType Quantitative+              , PAxis [ AxTitle "Number of Stars" ]+              ]++  in toVegaLite+       [ gaiaData+       , columns 4+       , facetFlow [ FName "Cluster", FmType Nominal ]+       , specification (asSpec [ mark Bar [], enc [] ])+       ]+++{-|++Earlier - in 'densityParallaxGrouped' - I used the Kernel-Density+Estimation support in Vega Lite 4 to show smoothed parallax+distributions, grouped by cluster. We can combine this with+the 'facetFlow' approach to generate a plot per cluster+of the parallax distribution. I have used 'DnExtent' to ensure+that the density estimation is done on the same grid for+each cluster.++The most important thing in this example is that I have+used a sensible number of columns (ending up in a three by three grid)!+The other significant changes to 'smallMultiples2' is that I have+used the 'FHeader' option to control how the facet headers+are displayed: the title (which in this case was @\"Cluster\"@)+has been hidden, and the per-plot labels made larger, but moved+down so that they lie within each plot. I am not 100% convinced+this is an intended use of 'HLabelPadding', but it seems to work!++<<images/vl/densitymultiples.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zUBRk-EIVp-D0Ygo2VyhAA2vdCrNICwcMoyNwAJ5gyBDPB8cyQAC67yhpmRCw0cVSUARhP4WJxnX4C0kEjBvhSYAAzL5sfdMHFARwkQdLndZi8MGzTiYcBoGqUYusMlJRNA2GJ6qhIRlRHgcgUsmx+HhoA1UejplB4AivhMRLIFbACIzIMEWFI9agmng8G97pArmh2VBMtrdQ0CUTKX9TeSDgBHLCwCQcBBsfTS3ELNgUTXwDjBBoABVK1rwsCWgqK7qhPO9G19-qdJLJSc6JrNkejscQGcTIYyhdT6cz4agCikFG5kGLGDHgtLUAAJBQhNETA0SOQqLQrGF2JweEw2CJqHOF0Z1048BxtLoACxMABWFHE0sgauagMITPeWVgQn4+WVHS1OprFE0TMY5TmiWI2l-KEC1aPAejEecNQOR160wGCdVzaB5UVQgnAAJgvTs7VgWCADFxHgUY2AAL37LwiIzeAs2dLBXSI9C4NPFgxAaHA2BYEh+XHSlIEbftGgtK0CHSKdH3EP0lTQJ4HiAA Open this visualization in the Vega Editor>++@+let trans = transform+            . density "plx" [ DnAs \"xkde\" \"ykde\"+                            , DnGroupBy [ \"Cluster\" ]+                            , 'DnExtent' 0 30+                            ]++    enc = encoding+          . position X [ PName \"xkde\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"Parallax\" ]+                       ]+          . position Y [ PName \"ykde\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"Density\" ]+                       ]+          . color [ MName \"Cluster\"+                  , MmType Nominal+                  , MLegend []+                  ]++    headerOpts = [ 'HLabelFontSize' 16+                 , 'HLabelAlign' 'AlignRight'+                 , 'HLabelAnchor' 'AEnd'+                 , 'HLabelPadding' (-24)+                 , 'HNoTitle'+                 ]++    spec = asSpec [ enc []+                  , trans []+                  , mark Area [ ]+                  ]++in toVegaLite+     [ gaiaData+     , columns 3+     , facetFlow [ FName \"Cluster\"+                 , FmType Nominal+                 , 'FHeader' headerOpts+                 ]+     , specification spec+     ]+@++-}++densityMultiples :: VegaLite+densityMultiples =+  let trans = transform+              . density "plx" [ DnAs "xkde" "ykde"+                              , DnGroupBy [ "Cluster" ]+                              , DnExtent 0 30+                              ]++      enc = encoding+            . position X [ PName "xkde"+                         , PmType Quantitative+                         , PAxis [ AxTitle "Parallax" ]+                         ]+            . position Y [ PName "ykde"+                         , PmType Quantitative+                         , PAxis [ AxTitle "Density" ]+                         ]+            . color [ MName "Cluster"+                    , MmType Nominal+                    , MLegend []+                    ]++      headerOpts = [ HLabelFontSize 16+                   , HLabelAlign AlignRight+                   , HLabelAnchor AEnd+                   , HLabelPadding (-24)+                   , HNoTitle+                   ]++      spec = asSpec [ enc []+                    , trans []+                    , mark Area [ ]+                    ]++  in toVegaLite+       [ gaiaData+       , columns 3+       , facetFlow [ FName "Cluster"+                   , FmType Nominal+                   , FHeader headerOpts+                   -- do not have access to plx field here+                   -- and xkde,ykde is not useful here as want to+                   -- sort by the xkde value when ykde is max+                   -- , FSort [ ByFieldOp "xkde" Median ]+                   ]+       , specification spec+       ]+++-- $intro-multiplot+-- There are four ways in which multiple views may be combined:+--+-- * The __facet operator__ takes subsets of a dataset (facets) and+--   separately applies the same view specification to each of+--   those facets (as seen with the 'column' function above).+--   Available functions to create faceted views:+--   'column', 'row', 'facet', 'facetFlow', and 'specification'.+--+-- * The __layer operator__ creates different views of the data but+--   each is layered (superposed) on the same same space; for example+--   a trend line layered on top of a scatterplot.+--   Available functions to create a layered view: 'layer' and 'asSpec'.+--+-- * The __concatenation operator__ allows arbitrary views (potentially+--   with different datasets) to be assembled in rows or columns.+--   This allows \'dashboards\' to be built.+--   Available functions to create concatenated views:+--   'vConcat', 'hConcat', and 'asSpec'.+--+-- * The __repeat operator__ is a concise way of combining multiple views+--   with only small data-driven differences in each view.+--   Available functions for repeated views: 'repeat' and 'specification'.+++{-|++We start with a \"basic\" plot for the dataset: the median value+of the parallax of the stars in each cluster.++<<images/vl/baseplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuKAjBkA04oBNYAXWVMUCCSAV3gBszIALIogBwGcUB6b+WAO4A6AOYBLIk2rpqHAKbwAxgHsAdkTnqhK6NwAiy6iIBCtRHO5MAbnJGxucDhviWbd7oRLc7Y2AFpYfwA2AEYggJCABj8SdDo5ENghVWU-JjlYfAUhIg4rHDwqADNleDgiMgpKKjYEeUrC6qgAcTgRRlVqaHQFAqbKSAAlAEEAfQBJAGFBgGUOrp74Pv6oNjoAD3nu3twVqD0AUQnpubRITu2l3ZXIOVG1zbOLxchGiABfRs+P68gAEg4inScEYLHYXF4biS4kk0iEYmU3EBwPsUL8dAkFisABYhAArDhqZa3VQqfBiVTtNBVKiPciQIpiOR0fCMSZ0WTOHBQIgATzYcg6ymgFNgDHe1yovMqDKZLMYD25kFgIhE8FsxEFZ2gcnJsFUSr5AsYAEdqPqiBJiGIbJBvmAJXhICpVIyqeRPu8gA Open this visualization in the Vega Editor>++@+let plx = position Y [ PName \"plx\", PmType Quantitative, PAggregate Median ]+    cluster = position X [ PName \"Cluster\", PmType Nominal ]+    enc = encoding . cluster . plx++in toVegaLite+      [ gaiaData+      , mark Bar []+      , enc []+      ]+@+-}++basePlot :: VegaLite+basePlot =+  let plx = position Y [ PName "plx", PmType Quantitative, PAggregate Median ]+      cluster = position X [ PName "Cluster", PmType Nominal ]+      enc = encoding . cluster . plx++  in toVegaLite+        [ gaiaData+        , mark Bar []+        , enc []+        ]+++{-|++We start our exploration by combining two visualizations, layering+one on top of the other. The base plot shows the same data as+'basePlot', and then on top we will show a horizontal line that+indicates the median parallax for all the stars in the sample.++<<images/vl/layeredplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zUAAkFELRJg0k5CotCsYXYnB4TDYImo31+RhBTjwHG0ugALEwAFYUcTrKB4WAATzaqAA2h1gJATDgNA1uKVUlApKJoGwxPVUBSrmgsmx+HhoA0hng+OYGZB4ASyPwJiJZKzYAQHkr3hAKVSaQccFhgpAXmAALrvM5iZms9loDqQAkFHl8gUHS5i2AsFg4AwIaUHWT8FmwMRiiVShoARywfvgHAQbH0uvSb3SkFEYkybHNwCeDyAA Open this visualization in the Vega Editor>++@+let plx = position Y [ PName \"plx\", PmType Quantitative, PAggregate Median ]+    cluster = position X [ PName \"Cluster\", PmType Nominal ]++    perCluster = [ mark Bar [], encoding (cluster []) ]+    allClusters = [ mark 'Rule' [] ]++in toVegaLite+      [ gaiaData+      , encoding (plx [])+      , 'layer' (map 'asSpec' [perCluster, allClusters])+      ]+@++For this visualization, the specification starts with the data+source and an encoding, but __only__ for the y axis (which means+that all layered plots use the same encoding for the axis). The+'layer' function introduces the different visualizations that+will be combined, each as there own \"specification\" (hence+the need to apply 'asSpec' to both @perCluster@ and @allClusters@).+Note that there is no x-axis encoding for the 'Rule', since the+data applies to all clusters (i.e. it should span the+whole visualization).++-}+layeredPlot :: VegaLite+layeredPlot =+  let plx = position Y [ PName "plx", PmType Quantitative, PAggregate Median ]+      cluster = position X [ PName "Cluster", PmType Nominal ]++      perCluster = [ mark Bar [], encoding (cluster []) ]+      allClusters = [ mark Rule [] ]++  in toVegaLite+        [ gaiaData+        , encoding (plx [])+        , layer (map asSpec [perCluster, allClusters])+        ]+++{-|++This example is similar to 'layeredPlot' but includes an x-axis+encoding for the second layer. We use this to show the range of the+data - so the minimum to maximum parallax range of each cluster - with+the 'Rule' type. The difference to the previous plot is that an+extra positional encoding is added ('Y2') to define the end point+of each line ('Y' is used as the start point).++<<images/vl/layereddiversion.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFACYCGKpGYoEEkArgE4A2VMKKADgM7oD0fRqQDuAOkTwU0egCN63WIwDGAewB2KWBtGqAtnwAiK+ogBCTANaw+0AG6xEpPrtLdNjG-cd8yFPo-hSAFpSYIA2AEYwkIicIIoZZlgI0lE1FSC4UmJFURRuW0hCWigAMxVGFzRMGhKoTlJGBSpauqgAcRdENjV6XRlFIqI2yAAlAEEAfQBJAGFRgGUevoHGIba6TmYAD2X+weKNyAMAURn5pcxIXv21w5HYSa3dq5vVyGHaAF9Pn4gvw6QYTwYhSKi4AhESAAEm4SjgLjYqC4vAEXlSEikslE8BUfDhCKc6KCzEk1lsABZRAArbjqdZQZikACeg0wAG1Pq1aJAXIwLC1INx4AAvWBUABMBCgKGZnHFVyU8GUSUgAM+dC0qmI8DU3RqGp5zMFpXgsGYxDYzyKUFIiEQjAc5AVUF0sB1pDUNsgsvlbAAjvRPShJOR4PY1Ya-t97tRDbzGgKrox6KrY5q1Nrdfq4xsoMyJSazRarTtvXaHU7NGwXLt1XnIMaapBTebLVdrfhbfbHY5q1ddLrvb6XZBA8HQyGI9GSjOwNGALqArUqHV6wUvagt4vtqCzZjydzDuWj9KDtSkVhfetQVRqU054A-L5AA Open this visualization in the Vega Editor>++@+let plx op = position Y [ PName \"plx\", PmType Quantitative, PAggregate op ]+    cluster = position X [ PName \"Cluster\", PmType Nominal ]++    median = [ mark Circle [ 'MSize' 20 ]+             , encoding (plx Median [])+             ]+    range = [ mark Rule [ ]+            , encoding+                . plx 'Min'+                . position 'Y2' [ PName "plx", PAggregate 'Max' ]+                $ []+            ]++in toVegaLite+      [ gaiaData+      , encoding (cluster [])+      , layer (map asSpec [ median, range ])+      , width 300+      , height 300+      ]+@++The 'MSize' option is used to change the size of the circles so that they+do not drown out the lines (the size value indicates the area of the mark,+and so for circles the radius is proportional to the square root of this+size value; in practical terms I adjusted the value until I got something+that looked sensible).++Note that the y axis is automatically labelled with the different+operation types that were applied - median, minimum, and maximum -+although there is no indication of what marks map to these operations.++-}+layeredDiversion :: VegaLite+layeredDiversion =+  let plx op = position Y [ PName "plx", PmType Quantitative, PAggregate op ]+      cluster = position X [ PName "Cluster", PmType Nominal ]++      median = [ mark Circle [ MSize 20 ], encoding ( plx Median []) ]+      range = [ mark Rule [ ], encoding . plx Min . position Y2 [ PName "plx", PAggregate Max ] $ [] ]++  in toVegaLite+        [ gaiaData+        , encoding (cluster [])+        , layer (map asSpec [ median, range ])+        , width 300+        , height 300+        ]+++{-|++In this example 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.++<<images/vl/layeredcount.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxhIBzWdAVwAcAjATz0MgGEAba5aAU1kgBdADRR45Sr3Lw+LAmXS0WkAMY1E0SKMjxkytdQ2QAvoOPERxSAAteAS3LXN+AEwBWAAzCraxKgcsZABudrwA7oGQPFQA1rwsiNQcHMbG3hCQACYy8IHEGdSwHMpO0LTIuAD0lQhhAHTkdtDW1PTc-L58GnVqWJUAIjTkAEKFcZXWQVLwlVi6fLATU9KV2dAz0nbwALTwOwBsAIz7u4ce2+v0HLyH8HWI6Nu28Jn8ddDIQVr5UBjYMnkSCRILR4LBkPF8KAgUDIABxObkZSJLD0fjfGHAgBKAEEAPoASTYWIAysjqKj0elMVBaBwAB7kykCamYyD9ACihOJZPwkBRaJZP1hvDxdMZfIF6OFYHMQLlsupkDCdkyzRYAGYPF4rAASZAqWxzErQMoVarLO6NZqtOp2dCVA1GmaW7YcJq8SpBAAsdQAVsh0IgMVBoE1rpE+PTnFAAHIUwVgdCoMA8MHIMC0fhgFRcHhU35B6AkuwAL0hYEOAA40lYOPBGOj8EQgdCYZA5rAYsp6GCQyLEGpMnZEEioTKMmoOJhATSMv5eBxMspONwFv2aVFMDGyLxB+hh6PlMxtJhXgI+a8DXvD0ja3OMtBGFnkegsCP4MVWZvruQb5FQUyW8WDObRonQOI2HQacLygSgGxMCdFSQyAJVIJD51CJcVzzddvzZQNYB3SA9yHEcxygE8oDPJsoCvFQb3Ikx8PbJ8X0lN8Py-DCxHpOw9HwRJkiQ+9N2YKFIAXbC+QMIxtDYitIAAR2oJAw3WMMpi0Xj+ISJIUhlBUIFEiA21hTtuwkzJxLAbZ9nk59FKjTQTOBUiDyY8c5xgXho0iKTlxk9RNAc9ioBUtSmhkOwtNc2E0LMzcApwtcqR4rciMidzgL5KjIBo2Csl4a9EGAuLWMc1930QT8NzZeA+IEsAhI4ESWIyGyyGSoLDBC0NKr5CKNCizT4m0BrdME-SjJIGaFUEEBjCAA Open this visualization in the Vega Editor>+++@+let trans = transform+            . aggregate [ opAs Count \"\" \"count\" ]+                        [ \"Cluster\" ]++    chanSort = [ ByChannel ChY, Descending ]++    baseEnc = encoding+              . position X [ PName \"Cluster\"+                           , PmType Nominal+                           , PSort chanSort+                           , PAxis []+                           ]+              . position Y [ PName \"count\"+                           , PmType Quantitative+                           , PAxis []+                           ]++    barEnc = baseEnc+             . color [ MName \"Cluster\"+                     , MmType Nominal+                     , MLegend [ 'LStrokeColor' \"gray\"+                               , 'LPadding' 10+                               ]+                     , MSort chanSort+                     ]++    labelEnc = baseEnc+               . 'text' [ TName \"count\", TmType Quantitative ]++    barSpec = asSpec [ barEnc [], mark Bar [] ]+    labelSpec = asSpec [ labelEnc [], mark 'Text' [ 'MdY' (-6) ] ]++    cfg = configure+          . configuration ('View' ['ViewStroke' Nothing])++in toVegaLite [ width 300+              , height 250+              , cfg []+              , gaiaData+              , title \"Number of stars per cluster\" [ TFontSize 18 ]+              , trans []+              , layer [ barSpec, labelSpec ]+              ]+@++Both axes have been dropped from this visualization since+the cluster name can be found from the legend and the+count is included in the plot. The same sort order is+used for the X axis and the color mapping, so that its+easy to compare (the first item in the legend is the+cluster with the most counts). Note that this changes the+color mapping (cluster to color) compared to previous+plots such as 'parallaxBreakdown'.++-}++layeredCount :: VegaLite+layeredCount =+  let trans = transform+              . aggregate [ opAs Count "" "count" ]+                          [ "Cluster" ]++      chanSort = [ ByChannel ChY, Descending ]++      baseEnc = encoding+                . position X [ PName "Cluster"+                             , PmType Nominal+                             , PSort chanSort+                             , PAxis []+                             ]+                . position Y [ PName "count"+                             , PmType Quantitative+                             , PAxis []+                             ]++      barEnc = baseEnc+               . color [ MName "Cluster"+                       , MmType Nominal+                       , MLegend [ LStrokeColor "gray"+                                 , LPadding 10+                                 ]+                       , MSort chanSort+                       ]++      labelEnc = baseEnc+                 . text [ TName "count", TmType Quantitative ]++      barSpec = asSpec [ barEnc [], mark Bar [] ]+      labelSpec = asSpec [ labelEnc [], mark Text [ MdY (-6) ] ]++      cfg = configure+            . configuration (View [ViewStroke Nothing])++  in toVegaLite [ width 300+                , height 250+                , cfg []+                , gaiaData+                , title "Number of stars per cluster" [ TFontSize 18 ]+                , trans []+                , layer [ barSpec, labelSpec ]+                ]+++-- TODO: can I plot the mean / median of the parallax for each cluster++{-|++As promised earlier (in 'skyPlot'), now that we have layers, we can+add graticules to a projection. In this case I create two graticule layers,+the \"base\" layer (@grats@), which creates the grey lines that cover+the map - using a spacing of 60 degrees (4 hours) for longitude and+15 degrees for latitude - and then an extra layer (@grats0@), which shows blue lines+at longitude seprations of 180 degrees+and latitude spacings of 90 degrees. In this case the central horizontal and+vertical lines represent 0 degrees, and the one at the left shows+-180 degrees. There are no latitude lines for -90 or +90 since the+default is to stop at ±85 degrees (see 'GrExtent' for a way to+change this).++I added the second graticule layer to see if I could get by without+labels for the grid lines, but decided this did not work out too well,+so ended with two layers, one each for the Right Ascension and+Declination values, using 'dataFromColumns' to manually create the+label positions and label content to display with the 'Text' mark.++<<images/vl/skyplotwithgraticules.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMAWADDgNOFAO7wAmK0GYAzAKwFGQAkAzgMZwC2AhtTChQAHVugD0YgG6xEPAHSJ4lAK4AjOfAD2Yjtx5SZPALQAbJbClY5AK1aaAdpEIRIQgE6brsdii2PMwJAoAJ5CsPxcsG7sPCiabpAAvs5QJjzBUdQA2kQQoBAFULxuANbU+YUFkKwoHiWwAOrklNQ4cnQplVA1deGYkIhusMFOuZXVtZr1APJCPOxKI5htHWOFQaF9UIiwmqzQPGGQa2DJJ5BksXwBA26x8OzKJluBNbBC2QBsBGAAjHQAXUSiTGZ0KgWKZX6Oz2ByO+CglxQ1zAgUG90ez3KE3e2V+AA4fgBOHBA4GdVHnWo8eysABm8S42ROeRZVR4rH4JgcihQyjI4QpXUgMRMmNiWwusWUXDkACUAIIAfQAkgBhOUAZTAAD4-oSwAB+MBImXy5XqrVgIy0b5gTCm2WK1UazXHLoQEFdAFCoo8Ur8BbRLG+qXI8psyDKNwmfioYSiCR3YgKJTQNTKVhRdgOFCwewoOQ5rhiAAimmUiAAQtH6mJoNJZGJeG83PXG-okfpZPBjDxjJ9fp8jDxfjgjMjVM9fvJ7JojHAeAK3HIUKxJKMPVAGW5eGgAmyXHM3FmI1v1gBxXiIfj2GWqTK+4XOy1u-p3rgPhJP8ZCEwAD1ve9H0PKpSwAURdLUgM-EDzyqWAlT-QD32AhJQK9D1MMKMFxnzHMyHgewbwPLcRU0bkElI89IDpeBYBMMh+GQzcaI4HgsRuXRYEifhJHgNxyHgTkEQ2I5+m5G9cLIkJxKgABHZQaV8ZFfGkViyOeHZ7CYm4VM4qBjw4tJAOwyppPGNIVP5F5aPoxj+AgqC3VE2TJUU5SlHudSLPWOIKN8D4bjohjdKgNUTEzPNvygNzb00LgiI4pIf0gbliKUGzsRChyJJ5TKBScWLNn4DyCy8tTwjMz1QQpCp1khbEyCWMAOigDikH8KB2HzaKirEyU83-NBRNUDkGKIwbNA+XzESuM8PUgSQOOUWBOUwHJ4MCEwp34IcqFElDrV+AAmH5IBanBZvBNLdv6M6DqgI6jG+UTLuugptruqAsEeyAjteqB3p-PJbtjfp8T+o7TvO962QBE5ZsgfDNEI4iFuFIb91ROzQq5XbXJK98EqS2MPrS+4+UK4L7LCi7+ri-oypU7yqtS9LeSymm8f6QDCbkyBmYq+AfMR2qxnqqpGuo4UyGe1YyI6xAusgQTkBGyNGdi2Bho08YxqzMx7ElRKyDILFEdDLsMfGZbIrW5ktrB-gjCwOh+qO2HqFdugPtBnbwZ+93DtaN7qDd6qCgRrokZRtGSMpGSdexwIcrpgOGaJqA50S+xkvJqyCtstP+BGfn3KU8rVJFtnIw5ovstp-g+eKgWher0WY9BIgfSYHN7DohPgBBRIgA Open this visualization in the Vega Editor>++@+let trans = transform+                . calculateAs+                  "datum.RA_ICRS > 180 ? datum.RA_ICRS - 360 : datum.RA_ICRS"+                  "longitude"++    axOpts field = [ PName field, PmType Quantitative ]++    enc = encoding+            . position Longitude (axOpts "longitude")+            . position Latitude (axOpts \"DE_ICRS\")+            . color [ MName \"plx\"+                    , MmType Quantitative+                    , MScale [ SType ScLog+                             , SScheme \"viridis\" []+                             ]+                    , MLegend [ LTitle "parallax" ]+                    ]+            . tooltip [ TName \"Cluster\", TmType Nominal ]++    stars = asSpec [ gaiaData, trans [], enc [], mark Circle [] ]+    grats = asSpec [ 'graticule' [ 'GrStep' (60, 15) ]+                   , mark 'Geoshape' [ MStroke "grey"+                                   , 'MStrokeOpacity' 0.5+                                   , 'MStrokeWidth' 0.5+                                   ]+                   ]+    grats0 = asSpec [ graticule [ GrStep (180, 90)+                                ]+                    , mark Geoshape [ ]+                    ]++    raData = 'dataFromColumns' []+                 . 'dataColumn' "x" (Numbers [ -120, -60, 60, 120 ])+                 . dataColumn "y" (Numbers [ 0, 0, 0, 0 ])+                 . dataColumn "lbl" ('Strings' [ "16h", "20h", "4h", "8h" ])++    decData = dataFromColumns []+                 . dataColumn "x" (Numbers [ 0, 0 ])+                 . dataColumn "y" (Numbers [ -45, 45 ])+                 . dataColumn "lbl" (Strings [ "-45", "45" ])++    encLabels = encoding+                . position Longitude (axOpts "x")+                . position Latitude (axOpts "y")+                . text [ TName "lbl", TmType Nominal ]++    raLabels = asSpec [ raData []+                      , encLabels []+                      , mark Text [ 'MAlign' 'AlignCenter'+                                  , 'MBaseline' 'AlignTop'+                                  , MdY 5+                                  ]+                      ]+    decLabels = asSpec [ decData []+                       , encLabels []+                       , mark Text [ MAlign AlignRight+                                   , MBaseline 'AlignMiddle'+                                   , 'MdX' (-5)+                                   ]+                      ]++in toVegaLite [ width 400+              , height 350+              , projection [ PrType Mercator ]+              , layer [ grats, grats0, stars, raLabels, decLabels ]+              ]+@++The layers are drawn in the order they are specified, which is why the+grid lines are drawn under the data (and labels).++You can see the distortion in this particular projection (the+<https://en.wikipedia.org/wiki/Mercator_projection Mercator projection>),+as the spacing between the latitude lines increases as you move towards the+bottom and top of the plot. There are a number of other projections you+can chose from, such as the 'Orthographic' projection I use in+'concatenatedSkyPlot'.++-}++skyPlotWithGraticules :: VegaLite+skyPlotWithGraticules =+  let trans = transform+                . calculateAs+                  "datum.RA_ICRS > 180 ? datum.RA_ICRS - 360 : datum.RA_ICRS"+                  "longitude"++      axOpts field = [ PName field, PmType Quantitative ]++      enc = encoding+              . position Longitude (axOpts "longitude")+              . position Latitude (axOpts "DE_ICRS")+              . color [ MName "plx"+                      , MmType Quantitative+                      , MScale [ SType ScLog+                               , SScheme "viridis" []+                               ]+                      , MLegend [ LTitle "parallax" ]+                      ]+              . tooltip [ TName "Cluster", TmType Nominal ]+              -- note: opacity doesn't really help here++      stars = asSpec [ gaiaData, trans [], enc [], mark Circle [] ]+      grats = asSpec [ graticule [ GrStep (60, 15) ]+                     , mark Geoshape [ MStroke "grey"+                                     , MStrokeOpacity 0.5+                                     , MStrokeWidth 0.5+                                     ]+                     ]+      grats0 = asSpec [ graticule [ GrStep (180, 90)+                                  ]+                      , mark Geoshape [ ]+                      ]++      -- hmmm, tried to use "ᴴ" / \u1D34 but this does not get converted+      -- properly (is there a UTF-8/16 issue going on, or am I+      -- just failing to understand modern text encoding yet again?)+      --+      -- this also affects ° / \u00b0 so not sure what's going on+      raData = dataFromColumns []+                   . dataColumn "x"+                     (Numbers [ -120, -60, 60, 120 ])+                   . dataColumn "y"+                     (Numbers [ 0, 0, 0, 0 ])+                   . dataColumn "lbl"+                     (Strings [ "16h", "20h", "4h", "8h" ])++      decData = dataFromColumns []+                   . dataColumn "x"+                     (Numbers [ 0, 0 ])+                   . dataColumn "y"+                     (Numbers [ -45, 45 ])+                   . dataColumn "lbl"+                     (Strings [ "-45", "45" ])++      encLabels = encoding+                  . position Longitude (axOpts "x")+                  . position Latitude (axOpts "y")+                  . text [ TName "lbl", TmType Nominal ]++      raLabels = asSpec [ raData []+                        , encLabels []+                        , mark Text [ MAlign AlignCenter+                                    , MBaseline AlignTop+                                    , MdY 5+                                    ]+                        ]+      decLabels = asSpec [ decData []+                         , encLabels []+                         , mark Text [ MAlign AlignRight+                                     , MBaseline AlignMiddle+                                     , MdX (-5)+                                     ]+                        ]++      -- don't know how to change the center++  in toVegaLite [ width 350+                , height 400+                , projection [ PrType Mercator ]+                , layer [ grats, grats0, stars, raLabels, decLabels ]+                ]++++{-|++Instead of layering one view on top of another (superposition), we can+place them side by side in a row or column (juxtaposition). In+Vega-Lite this is referred to as /concatenation/:++<<images/vl/concatenatedplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zULqiYkIIhADaHUKpxMOA0DW4pXWnSkomgbDE9VQQM6VzQWTY-Dw0AaQzwfHMqSg8AAnmR+BMRLJ4bACG97phiQV0ZjsQdLoTILAWCwcAYEOSDrJ+HDYGIOSSyQ0AI5YUXwDgINj6SAvKqq17vCDIzAgsEHCFrTUZGEiOEIiobKCo4DMrE4vFmaZE0kCqARKliGkqo2nRlI22sqC1Lkcrk8vmSBpCkVilLOyUHGVyhXy5XqjDp1UAXXekAAJBQhNETA0SOQqLQrGF2JweEw2CJqIXi0Yq048BxtLoACxMABWFHEUMgX0ybERaCeDyAA Open this visualization in the Vega Editor>++@+let enc field = encoding+                 . position X [ PName \"Cluster\", PmType Nominal ]+                 . position Y [ PName field, PmType Quantitative, PAggregate Median ]++    parallaxes = [ mark Bar [], enc \"plx\" [] ]+    magnitudes = [ mark Bar [], enc \"Gmag\" [] ]++    specs = map asSpec [ parallaxes, magnitudes ]++in toVegaLite+      [ gaiaData+      , 'vConcat' specs+      ]+@++The 'hConcat' function would align the two plots horizontally,+rather than vertically (and is used in 'concatenatedSkyPlot').++Note that as the axes are identical apart from the field for the y axis,+the encoding has been moved into a function to enforce this constraint+(this ensures the x axis is the same, which makes it easier to visually+compare the two plots). However, there is no requirement that the+two plots be "compatible" (they could use different data sources).++-}+++concatenatedPlot :: VegaLite+concatenatedPlot =+  let enc field = encoding+                   . position X [ PName "Cluster", PmType Nominal ]+                   . position Y [ PName field, PmType Quantitative, PAggregate Median ]++      parallaxes = [ mark Bar [], enc "plx" [] ]+      magnitudes = [ mark Bar [], enc "Gmag" [] ]++      specs = map asSpec [ parallaxes, magnitudes ]++  in toVegaLite+        [ gaiaData+        , vConcat specs+        ]+++{-|++The alignment of the plots can be adjusted with 'spacing', which we+use here to remove the vertical gap between the two plots (the+example is written so that we can see the only difference between+the two plot specifications is the addition of @'PAxis' []@ to the+parallax plot).++<<images/vl/concatenatedplot2.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zULqiYkIIhADaHUKpxMOA0DW4pXWnSkomgbDE9VQQM6VzQWTY-Dw0AaQzwfHMqSg8AAnmR+BMRLJ4bACCkoLAFmwKIQmng8G97phiQV0ZjsQdLoTILAWCwcAYEOSDrJ+HDYGIhSSyQ0AI5YeXwDgINj6SAvKr617vCDIzAgsEHCFrY0ZGEiOEIiobKCo4C8rE4vFmaZE0lSqARKliGl6m2nblI938qC1EVCkViiWSBoyuUKumQJX+yBqjVazW6w0YIv6gC670gABIKEJoiYGiRyFRaFYwuxODwmGwRNQa3WjK2nHgONpdAAWJgAKwo4ihkAoJSE8MRYF8Fa+mTYK+ATweQA Open this visualization in the Vega Editor>++@+let enc field flag = encoding+                       . position X ([ PName \"Cluster\", PmType Nominal ] +++                                     if flag then [ PAxis [] ] else [])+                       . position Y [ PName field, PmType Quantitative, PAggregate Median ]++    parallaxes = [ mark Bar [], enc \"plx\" True [] ]+    magnitudes = [ mark Bar [], enc \"Gmag\" False [] ]++    specs = map asSpec [ parallaxes, magnitudes ]++in toVegaLite+      [ gaiaData+      , 'spacing' 0+      , vConcat specs+      ]+@++Even though we set 'spacing' to @0@ there is still a small gap between+the plots: this can be removed by using @'bounds' 'Flush'@, but we'll+leave using that until the grand finale.++-}++concatenatedPlot2 :: VegaLite+concatenatedPlot2 =+  let enc field flag = encoding+                         . position X ([ PName "Cluster", PmType Nominal ] +++                                       if flag then [ PAxis [] ] else [])+                         . position Y [ PName field, PmType Quantitative, PAggregate Median ]++      parallaxes = [ mark Bar [], enc "plx" True [] ]+      magnitudes = [ mark Bar [], enc "Gmag" False [] ]++      specs = map asSpec [ parallaxes, magnitudes ]++  in toVegaLite+        [ gaiaData+        , spacing 0+        , vConcat specs+        ]+++{-|++In 'skyPlotWithGraticules' I used the 'Mercator' projection to display+the stars on the sky, but promised I would also show you data using the+<https://en.wikipedia.org/wiki/Orthographic_projection_in_cartography Orthographic projection>.++The main specification (that is, the argument of 'toVegaLite') starts+with a change to the plot defaults, using 'configure' to ensure+that no border is drawn around the plot (note that in 'combinedPlot'+I do the same thing, but by setting the stroke color to+@Just \"transparent\"@ rather than @Nothing@). The default data+stream is set up, to ensure we have \"longitude\" and+\"DE_ICRS" values to display. It then has three+versions of the same visualization, varying only on rotation angle and+label, stacked horizontally with 'hConcat'.++Each plot - created with the @rSpec@ helper function - defines+a plot size, uses the 'Orthographic' projection with the+given rotation (the @lambda@ term of 'PrRotate') to change the+center of the display, and then the plot itself is formed from+four layers:++1. 'sphere' is used to indicate the area of the plot covered by the sky+   (filled with a blue variant);++2. graticules are drawn at every 30 degrees (longitude, so 2 hours+   in Right Ascension) and 15 degrees (latitude);++3. the stars are drawn using color to encode the parallax of the+   star and the symbol shape the cluster membership (although the density+   of points is such that it can be hard to make the shapes out);++4. and a label is added at the center of the plot to indicate the+   Right Ascension (the label could be determined automatically from+   the rotation angle, but it was easier to just specify it directly).++Since the data values have two different encodings - 'color' and 'shape' -+there are two legends added. I place them in different locations using+'LOrient': the parallax goes to the right of the plots (which is the+default) and the symbol shapes to the bottom. Both use larger-than-default+font sizes for the text (title and label).++<<images/vl/concatenatedskyplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxQSTJ5k8oAbdRAcwEtoBXAEwFNIAaY8pADG8WkLa140HvkgcpbLADoASgEEA+gEkAwioDKYAHxgAjAA4ADGAD8Yee2XrtewwFowAZgBs1-A8VVTV0DSAEwAF9iAF1+CEgACyEGEWgaInIycigErmZGBLT8T0tLOOzIAHdmDmgEmhKy8PiAB1h0ACsuIWhmBhpgGABPFpkoTDr0RgQWhOYhPih26CkxgjdTACYysB3LaIjywUkhrlh05pIs7IoseFgAawHIVGZaWhpKWnmuACNaNg8XhQaAjMaQRhcdDIBLwUaQQ6XQQOeDPZCzM5jOCAqI3CCIvGkJG3e5PfDXQlQZBwdAPLgAdRqdRoliUAFYjpTINT2nTPtMuEM+MTBDzaVwAPIteBCVhC-Csjkiiig+GySHQ2Hw5UErko57TKTzCRjQbUrgtACyzEQmHSJWBpjZB1xeN1NwpN0gd0enxa6BtaU5Xq4iGSHBtjAGyviyXo53JMYory4tA4ftoAA9hZSKsgRLRTdyhLksOCAG7MWA1ZjUYHDNV0KYI4Nc1XggCObCQvRWvXLQKT8ULkMQ6cTua9mGYoaKS3yhRzk+O8F+qYAYgxoPpmAAvMamAAsrdzMFYhb991EkmzJ7b564m8Q273B+8Q8iSfdXMkvc4RZTNNPgAEQAURcUJ63bT4ux7VgjQHFsk25LVTQ-F4ZyA2QdABc1zjvL1oNkW0sBtUQl2XSAR1DcciWXQRp1nT5fnQaBoHQHACLxKjVw3Lcd33Ggjy4wiH0+IRcOkfCP3iXtCyfF9BPwUx33oz9l2-QkYHQdBaF6FpnkA2jIBwtg8MWBtwRIsiPk07j6CYVh-0MzDjIclh2G4CyiKgWDn3g-seFdQlguyOyIE9CofTJOjJzkeUwCVSjRHyRBxNnM4KLbMFPmkTMg2Q34qFTG1wXYgydS4uQpFRclIHLURAWofACEGWh-k+cx6nrbNlO2esEssCIDiq0Nw0jaNKLyudBiMz52o+KCcuIjibKQyjfycry6rm2QhSWxtID83sEKCkSm0czyANcz5bxBZbfO7fy+2YRDQpud6SE+6Jwm-SLEjyAo50aVsqiZepilKUG2k6bpen6OqfMgCYEimGY5gWetllWdI9mBfY7J404E0IYlIsEaKXPeT4UqEP4ASBe7Do1GE4TO5VqpWNEMVgLFYBxYlwtirTKYnOKxTpRlagh3Z2XO7kaT5dVef25CJclaVZVBFk5eQpGWdQsJcyF+J9Tqw1enEC86vNK0bTtFqHTMZ0Ik+-E73JklfVkf1AyykMw3QCMmEmuK4wd4W4t2qAWizf2uXzUQi3zUsKyrGs6yZ8F6CjE2KiR46Atewc1KorhR1oz2tMY59PmrIH49PSQ11oBSBIPY8ZJBMSfavd54FvLuz2geT+NfITVPot2wvlzarpc1NjLAiD9G8h6jqek7AvW8XDbFyjo5MyTMvO2T1+sxByNPuhy5o0PS5rudIBYtiOMbn9eNbselLMTu1NknuUAJJmSku-LSclHzfzfB+ae5A86yR0npZgBkdo3WwsffCWdPgX3IvAi6HlnKoMXvNBgBCvIHU7JvIub0dSCw9hzUWkctIcASklOKKVGBpVkHTZ8J89br2mmAigRVkAlUQGVdAFVjZVTNqQeqjUuDNUIG1DqsgtjdSgL1XYA0WTDTzpAMaQcJr7zbFwfKC8sJ0A6hQ7Bq1L62VnkaeeRDLGQH2lg2QhcXpvVnqQra11iGyDupZGCVDvFBVoSFS4P04Gcn+rkBcwMoaXDBtLBoySvQwy6D0PoXC5FIxRmjOEGMLLY2kOkLYeNdgjRSScTKLUyYMNJFTD4shab00BGvZmUJWbwn0bIs0PM+YCxCvQ08jCq4UHVlLZkCpdaUXVvyFWQj4jqylDKOUOs2Gnn1j0w2lUOYDIhAgS2Jo0TSDtraEmBAnZOhdHQxp4zmk+wDLXUagdg5RhMVpcOJNJmCEPrHQepdE7WzkSnLgZZPiVmrBGTOITZA5x3lNdeXjTorIoNRMc996LI2rExWQ9dFzX2HJ-Nu49lJ-3-sPMFkBpQIH7sC6lEDyU-xUjAr8ji-zbTkYfZeIRV42M8WE9FeCUJsxxaeQ+plzLXwRVAHBi10JYsrkPR+zFWLsU4kPZufFnztyElS0uEDxIYIxYIFlUCJ4co0vLdiul9IWOMjK0BQqFV2Nwb4y6hDeVoPwf4rplC4LhIRJEt0YyuQTOQiwmg2yuQcLycIDK0kUWHUEfLERYiJFSMpP0mqzwGoMyUa1KiqioCHg0ZALRGx+pQEGno9540Q7fO4oIlxblrEePdaRexyKP7coCa49x8qN7BtFV6shg7jLBILiK7esD1Jumib9GI5RhAMFeF8uRlYuCVHObyMYiAJC0FdmugZ4RIBsFgK0nIbEWjIFwAAekfQgSoSgPIJDYL8MyZxki8OfEoZIWBH3AXQGwRgAAhK9dJH0JAHIweAj67h4Vg-BxDKJH0IeYPANw8AcPeBUrh0wlg3ArH+FwUw8AlC2jcLkeA3BYBKGgMgcsWUXiYDuDNFJ9LRGSooAAcTuFuyAR6sBrhTdxZwArsGKHE+-OlcdiKyb4VpflrgZNiZU9xLgGggUabk5cUKrpdSQAACQQruJ8Qo0B71PsfWh99rBP2-CUH0R9FnENobcN8aQ9nDxKA6MgfoIAIhAA Open this visualization in the Vega Editor (although the link is long, and may not work with Internet Explorer)>++@+let trans = transform+              . calculateAs+                \"datum.RA_ICRS > 180 ? datum.RA_ICRS - 360 : datum.RA_ICRS\"+                \"longitude\"++    axOpts field = [ PName field, PmType Quantitative ]+    legend ttl o = MLegend [ LTitle ttl+                           , 'LOrient' o+                           , 'LTitleFontSize' 16+                           , 'LLabelFontSize' 14+                           ]+    enc = encoding+            . position Longitude (axOpts \"longitude\")+            . position Latitude (axOpts \"DE_ICRS\")+            . color [ MName \"plx\"+                    , MmType Quantitative+                    , MScale [ SType ScLog+                             , SScheme \"viridis\" []+                             ]+                    , legend \"parallax\" 'LORight'+                    ]+            . shape [ MName \"Cluster\"+                    , MmType Nominal+                    , legend \"cluster\" 'LOBottom'+                    ]+            . tooltip [ TName \"Cluster\", TmType Nominal ]++    stars = asSpec [ enc [], mark Point [] ]+    grats = asSpec [ graticule [ GrStepMinor (30, 15) ]+                   , mark Geoshape [ MStroke \"grey\"+                                   , MStrokeOpacity 0.5+                                   , MStrokeWidth 0.5+                                   ]+                   ]++    lblData r h0 =+      let r0 = -r+          lbl = h0 <> \"h\"+      in dataFromColumns []+         . dataColumn \"x\" (Numbers [ r0 ])+         . dataColumn \"y\" (Numbers [ 0 ])+         . dataColumn \"lbl\" (Strings [ lbl ])++    encLabels = encoding+                . position Longitude (axOpts \"x\")+                . position Latitude (axOpts \"y\")+                . text [ TName \"lbl\", TmType Nominal ]+    labels r h0 = asSpec [ lblData r h0 []+                         , encLabels []+                         , mark Text [ MAlign AlignCenter+                                     , MBaseline AlignTop+                                     , MdY 5+                                     ]+                         ]++    bg = asSpec [ 'sphere', mark Geoshape [ MFill \"aliceblue\" ] ]++    rSpec r h0 = asSpec [ width 300+                        , height 300+                        , projection [ PrType 'Orthographic'+                                     , 'PrRotate' r 0 0+                                     ]+                        , layer [ bg, grats, stars, labels r h0 ]+                        ]++    s1 = rSpec (-120) \"8\"+    s2 = rSpec 0 \"12\"+    s3 = rSpec 120 \"4\"++    setup = configure . configuration (View [ ViewStroke Nothing ])++in toVegaLite [ setup []+              , gaiaData+              , trans []+              , 'hConcat' [ s1, s2, s3 ] ]+@++-}++concatenatedSkyPlot :: VegaLite+concatenatedSkyPlot =+  let trans = transform+                . calculateAs+                  "datum.RA_ICRS > 180 ? datum.RA_ICRS - 360 : datum.RA_ICRS"+                  "longitude"++      axOpts field = [ PName field, PmType Quantitative ]+      legend ttl o = MLegend [ LTitle ttl+                             , LOrient o+                             , LTitleFontSize 16+                             , LLabelFontSize 14+                             ]+      enc = encoding+              . position Longitude (axOpts "longitude")+              . position Latitude (axOpts "DE_ICRS")+              . color [ MName "plx"+                      , MmType Quantitative+                      , MScale [ SType ScLog+                               , SScheme "viridis" []+                               ]+                      , legend "parallax" LORight+                      ]+              . shape [ MName "Cluster"+                      , MmType Nominal+                      , legend "cluster" LOBottom+                      ]+              . tooltip [ TName "Cluster", TmType Nominal ]++      stars = asSpec [ enc [], mark Point [] ]+      grats = asSpec [ graticule [ GrStepMinor (30, 15) ]+                     , mark Geoshape [ MStroke "grey"+                                     , MStrokeOpacity 0.5+                                     , MStrokeWidth 0.5+                                     ]+                     ]++      -- make the user work out what the new central location is+      lblData r h0 =+        let r0 = -r+            lbl = h0 <> "h"+        in dataFromColumns []+           . dataColumn "x" (Numbers [ r0 ])+           . dataColumn "y" (Numbers [ 0 ])+           . dataColumn "lbl" (Strings [ lbl ])++      encLabels = encoding+                  . position Longitude (axOpts "x")+                  . position Latitude (axOpts "y")+                  . text [ TName "lbl", TmType Nominal ]+      labels r h0 = asSpec [ lblData r h0 []+                           , encLabels []+                           , mark Text [ MAlign AlignCenter+                                       , MBaseline AlignTop+                                       , MdY 5+                                       ]+                           ]++      bg = asSpec [ sphere, mark Geoshape [ MFill "aliceblue" ] ]++      rSpec r h0 = asSpec [ width 300+                          , height 300+                          , projection [ PrType Orthographic+                                       , PrRotate r 0 0+                                       ]+                          , layer [ bg, grats, stars, labels r h0 ]+                          ]++      s1 = rSpec (-120) "8"+      s2 = rSpec 0 "12"+      s3 = rSpec 120 "4"++      setup = configure . configuration (View [ ViewStroke Nothing ])++  in toVegaLite [ setup []+                , gaiaData+                , trans []+                , hConcat [ s1, s2, s3 ] ]+++-- $intro-repeat+-- Creating the same plot but with a different field is common-enough+-- that Vega-Lite provides the 'repeat' operator.+++{-|++The 'concatenatedPlot' example can be extended to view the+distribution of several fields - in this case Right Ascension,+Declination, parallax, and magnitude:++<<images/vl/repeatplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMwYHsDuGYA2pAEoCCA+gJIDCpAypADRQAiAojfU65PABsAHiygBxALZIA5pAC6AX2bgoAZ0QBjQqAgRIU6AGtCkAEZJoLFXoAmqJNuu7IAV2gCTACxQp4q9AD0AdBIeAB00gCWKJ4upi6qsNAaOAB2KLDpYSkSAWw4LtIAQm6GsAGeAG6w0kgBUqoZ0BXVtQF2KHW1kUgAtEh9AGwAjIP9wwAMvZ2mArDDSGGpOL2eyDZJYSiqlVa6zgBmONBSaJg6+87wFomOl5eQkjImqS4Spkl7984U3Iwvbw+lmU3yuwgB70+INB7C4dH+mEgr0hwKc90gsEoghEiORQMgaN0CkJxP2SicGNSKRskVSsnOhMgOKwkAOkVgAhsJloAgSTVEkBQAE9EC8cBJaUgPOT0UK7t9WezOdoYAhkGcoNB8JAZQqZNI4LUMiYJLAaUhUl90cLRYiAI4uC0oaKoSLVAn3UlElS6yAAElUGjWUi8Pj8gQCrUWURicTCkRwAUDwbqUd6Ami5UqABYwgArVRpL6QFKpNn0rDEhRAA Open this visualization in the Vega Editor>++@+let enc = encoding+           . position X [ PName \"Cluster\", PmType Nominal ]+           . position Y [ 'PRepeat' 'Row', PmType Quantitative, PAggregate Median ]++    spec = asSpec [ gaiaData+                  , mark Bar []+                  , enc [] ]++    rows = [ \"RA_ICRS\", \"DE_ICRS\", \"plx\", \"Gmag\" ]++in toVegaLite+      [ 'repeat' [ 'RowFields' rows ]+      , 'specification' spec+      ]+@+++This more compact specification replaces the data field name+(for example @'PName' \"plx\"@) with a reference to the repeating field+('PRepeat') either as a 'Row' or 'Column' depending on the desired+layout. We then compose the specifications by providing a set of+'RowFields' (or 'ColumnFields') containing a list of the fields to which+we wish to apply the specification (identified with the function+'specification' which should follow the repeat function provided to+toVegaLite).++-}++repeatPlot :: VegaLite+repeatPlot =+  let enc = encoding+             . position X [ PName "Cluster", PmType Nominal ]+             . position Y [ PRepeat Row, PmType Quantitative, PAggregate Median ]++      spec = asSpec [ gaiaData+                    , mark Bar []+                    , enc [] ]++      rows = [ "RA_ICRS", "DE_ICRS", "plx", "Gmag" ]++  in toVegaLite+        [ repeat [ RowFields rows ]+        , specification spec+        ]+++{-|++If we want to plot more than one map from the same table of data+we need to do the lookup in the other order, using lookup to add the+geographic data to the data table. Charting this way requires+specifiying a few things differently than in the previous+choropleth example ('choroplethLookupToGeo'):++  * We're using 'LuAs' in 'lookup', rather than 'LuFields', which lets+    us use all the fields (columns) in the source rather than a specified+    subset.+  * We use a different set of geographic features (state rather than county+    outlines) from @usGeoData@.+  * The plot is defined as a 'specification', but does not directly refer+    to the value being displayed. This is set \"externally\" with the+    call to 'repeat'. Since we have just had an example with+    'RowFields', this time we use 'ColumnFields' to stack the maps+    horizontally.+  * Since the different fields have vastly-different ranges (a maximum of+    roughly 0.01 for \"engineers\" whereas the \"population\" field is+    a billion times larger), the color scaling is set to vary per field+    with 'resolve'.++<<images/vl/choroplethlookupfromgeo.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmDOB7ANgN1pAXGYl4GMBDZDbXfFRaLKASwDsATWAB1ifYBdIBfHgGnBQ4bQtzKQKyAK4BbejQDakFohbTkY2ogX8o7AOYNYsaPEh7IAC2nRotIvQSQAugKF42+GqAgRInNCE9PAAZlSySkJ+ONExUITm2JAGsIgWcTGQodCIkWSZ8ZCMYoQ+hfFQtsg01pycLPCYAPTNQQDuAHRGnDYARtLwphT0nFydFLLN6AaE07CzzbKJY9DNjIj48OulzYMAtACMAAyynQBWSLoVReHQy+I42bBitqRQ8JxizpacAJ5sWqcNSIS46Xg3CDuSpZADWsD+tVojEgN2hMMgyEQiFh0hYSJRhR4cRcgiyy2gsJ8eECOPekD6mnwVMsn1y8IA8ixCPhaP8aMdOgAmX4A+mpRDwKyEQHo-wlL7lSqQaq1Kz1RotNqELo9fqDYY6MajCZ5eaLGZzZafUzrTbbBVzVTqTScbT0AD6hmMpngHpsdgcwQQE3gqFRMTlUHayN6NAAzMdjmS-CpcudYPg3eCJP9AcliH1fQBVeBlKOQdgURgMAxKopSKj15WhWiwZAoiQiF6PSQoOQKKNZPP0gCO0mCbq+bvQGRhUBIqSY1KobdGQLUFigBiCNa4ABlDHHsInjsTKkOPtL809W+3O9u0luAmLahKwYO4uewOjIAASAgrFgZY1Q1JpWktbo+X6TptGaQDgLmS19mQPlYGmAAWC4rjnKARlbOsyGJHggA Open this visualization in the Vega Editor>++@+let popEngHurrData = dataFromUrl \"https:\/\/raw.githubusercontent.com\/vega\/vega\/master\/docs\/data\/population_engineers_hurricanes.csv\" []++    plotWidth = 300++    viz = [ popEngHurrData+          , width plotWidth+          , transform+            . lookup \"id\" (usGeoData \"states\") \"id\" ('LuAs' \"geo\")+            $ []+          , projection [PrType AlbersUsa]+          , encoding+            . shape [MName \"geo\", MmType GeoFeature]+            . color [MRepeat 'Column', MmType Quantitative, MLegend [LOrient 'LOTop', 'LGradientLength' plotWidth]]+            $ []+          , mark Geoshape [MStroke \"black\", MStrokeOpacity 0.2]+          ]++in toVegaLite+   [ specification $ asSpec viz+   , resolve+     . resolution (RScale [(ChColor, Independent)])+     $ []+   , repeat ['ColumnFields' [\"population\", \"engineers\", \"hurricanes\"]]+   ]+@++By moving the legend to the top of each visualization, I have taken+advantage of the fixed with (here 300 pixels) to ensure the+color bar uses the full width (with 'LGradientLength').++-}++choroplethLookupFromGeo :: VegaLite+choroplethLookupFromGeo =+  let popEngHurrData = dataFromUrl "https://raw.githubusercontent.com/vega/vega/master/docs/data/population_engineers_hurricanes.csv" []++      plotWidth = 300++      viz = [ popEngHurrData+            , width plotWidth+            , transform+              . lookup "id" (usGeoData "states") "id" (LuAs "geo")+              $ []+            , projection [PrType AlbersUsa]+            , encoding+              . shape [MName "geo", MmType GeoFeature]+              . color [MRepeat Column, MmType Quantitative, MLegend [LOrient LOTop, LGradientLength plotWidth]]+              $ []+            , mark Geoshape [MStroke "black", MStrokeOpacity 0.2]+            ]++  in toVegaLite+     [ specification $ asSpec viz+     , resolve+       . resolution (RScale [(ChColor, Independent)])+       $ []+     , repeat [ColumnFields ["population", "engineers", "hurricanes"]]+     ]+++{-|++We can combine repeated rows and columns to create a grid of+views, such as a scatterplot matrix, adding in color+encoding to separate out the clusters:++<<images/vl/splomplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMoIRgewHcMwBtSAJQEEB9ASQGFyBlSAGigBEBROxl9yPAA2ADzZQA4gFskAc0gBdVuByQAxniEBXKQDtiZKr2bjI3Y-yjCxA6XMUqAvstwBnRGuLZVM6AGsvSFcASwAvWGIAVgEUAE9EYkE8YN00ZxVcABNUJC8M1S1oIUSACxQUeFd0AHpq6CQCADpZYJQSrQAjLVdYaA1U2FTGjSlqjjwtWQAhQr9YapKAN1hZJGqZVxReheXV6uyUNdXgpABaJDOANgBGS-PrgAZTw46hWGukRt08U5LkTN6jRQrkWbHyuAAZnhoDI0JhvDhVPAkNAenlERjJDJ5JhILodB1emDMYiKDQGCZcfipIToMSSbhrIlqbT6QyzDwKSwqQSiS4GVBYNQmTyaUTwThHBKpYj0qTBhpMikcVgJepNNDAhDgrAhJlEvRtJs+VA4gkqXgpCkkMU5RjIGJ4ZBtbr9U64IhUIkNNo9JBnKb4hFcQBHLRIVKtVDBZb+-mk2JanV6wIe5BwqDQQhxwPmqBhiMoKNF2MyyVOfmQAAkrjUfxkpXKlRq1V2nxabU6jWCeGqtfrazbpyErXmiwALI0AFauPD6Sv9bUq4BSxxAA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PRepeat Column, PmType Quantitative ]+            . position Y [ PRepeat Row, PmType Quantitative ]+            . color [ MName \"Cluster\", MmType Nominal ]++    spec = asSpec [ gaiaData+                  , mark Point [ MSize 5 ]+                  , enc [] ]++    fields = [ \"RA_ICRS\", \"DE_ICRS\", \"plx\", \"Gmag\" ]++in toVegaLite+      [ repeat [ RowFields fields, ColumnFields fields ]+      , specification spec+      ]+@++To be honest, this is not the best dataset to use here, as+there is no direct correlation between location (the @RA_ICRS@+and @DE_ICRS@ fields) and the other columns, but it's the+dataset I chose, so we are stuck with it.++Once you have sub-plots as a specification, you can combine+them horizontally and vertically to make a dashboard style+visualization. Interested parties should check out the+<https://github.com/gicentre/elm-vegalite/tree/master/docs/walkthrough#building-a-dashboard-1240 Building a Dashboard> section of the+Elm Vega-Lite Walkthrough for more details.++-}++splomPlot :: VegaLite+splomPlot =+  let enc = encoding+             . position X [ PRepeat Column, PmType Quantitative ]+             . position Y [ PRepeat Row, PmType Quantitative ]+             . color [ MName "Cluster", MmType Nominal ]++      spec = asSpec [ gaiaData+                    , mark Point [ MSize 5 ]+                    , enc [] ]++      fields = [ "RA_ICRS", "DE_ICRS", "plx", "Gmag" ]++  in toVegaLite+        [ repeat [ RowFields fields, ColumnFields fields ]+        , specification spec+        ]+++-- $intro-interactivity+-- Interaction is enabled by creating /selections/ that may be combined with+-- the kinds of specifications already described. Selections involve three+-- components:+--+--  * __Events__ are those actions that trigger the interaction such as+--    clicking at a location on screen or pressing a key.+--+--  * __Points of interest__ are the elements of the visualization with+--    which the interaction occurs, such as the set of points selected+--    on a scatterplot.+--+--  * __Predicates__ (i.e. Boolean functions) identify whether or not+--    something is included in the selection. These need not be limited+--    to only those parts of the visualization directly selected through+--    interaction.++{-|++The next several plots show different types of selection -+select a single point, a range of plots, or follow the mouse - and+all have the same basic structure. To avoid repetition, and mistakes,+I am going to introduce a helper function which creates the+plot structure but without the selection definition, and then+use that to build up the plots.++The helper function, 'selectionProperties', takes two arguments, which are+the selection name and the plot title. The selection name is used+to identify the selection, as a visualization can support multiple+selections, and the plot title has been added mainly to show some+minor customization (the use of 'TOrient' to move the title to the+bottom).++The definition of this helper function is:++@+selectionProps selName label =+  let posOpts field = [ PName field+                      , PmType Quantitative+                      , PScale [ 'SZero' False ]+                      ]++      enc = encoding+               . position X (posOpts \"Gmag\")+               . position Y (posOpts \"plx\")++               . color [ 'MSelectionCondition' ('SelectionName' selName)+                           [ MName \"Cluster\", MmType Nominal ]+                           [ 'MString' "grey" ]+                       ]++               . 'opacity' [ MSelectionCondition (SelectionName selName)+                            [ 'MNumber' 1.0 ]+                            [ MNumber 0.3 ]+                         ]++               . 'size' [ MSelectionCondition (SelectionName selName)+                            [ MNumber 40 ]+                            [ MNumber 5 ]+                         ]++      trans = transform+                 . 'filter' ('FExpr' \"datum.DE_ICRS < -20\")++  in [ gaiaData+     , trans []+     , mark Point []+     , enc []+     , title label [ TOrient SBottom ]+     ]+@++The three non-selection-related features added here are that+'SZero' is used to tell Vega Lite that we do not need 0 displayed+on either axis, which leads to a \"tight\" bounding box around+the data, a 'filter' is used to select a subset of rows, namely+only those with a declination less than -20 (via 'FExpr'),+and the plot title is moved to the bottom with 'TOrient'.++The main change is that the selection is used in the encoding section,+identified by name, using 'SelectionName' and the supplied+argument. It is used as a filter for the encoding section, where+'MSelectionCondition' defines the properties to use+when the selection occurs (the first list of properties)+and when it does not (the second list). This is used for+three different encodings:++ - 'color', where the selected star is labelled by its+   cluster color, and all the other are grey;++ - 'opacity', so that the selected star is fully opaque+   whereas un-selected stars are partially transparent;++ - and 'size', so that the selected star is much bigger+   than the others.++When no selection has been made - such as when the visualization+is first created - then all points are encoded with the+\"selected\" case (so colorful, fully opaque, and large in this+case).++-}++selectionProperties ::+  T.Text+  -- ^ The selection name+  -> T.Text+  -- ^ The title for the plot+  -> [PropertySpec]+selectionProperties selName label =+  let posOpts field = [ PName field+                      , PmType Quantitative+                      , PScale [ SZero False ]+                      ]++      enc = encoding+               . position X (posOpts "Gmag")+               . position Y (posOpts "plx")++               . color [ MSelectionCondition (SelectionName selName)+                           [ MName "Cluster", MmType Nominal ]+                           [ MString "grey" ]+                       ]++               . opacity [ MSelectionCondition (SelectionName selName)+                            [ MNumber 1.0 ]+                            [ MNumber 0.3 ]+                         ]++               . size [ MSelectionCondition (SelectionName selName)+                            [ MNumber 40 ]+                            [ MNumber 5 ]+                         ]++      trans = transform+                 . filter (FExpr "datum.DE_ICRS < -20")++  in [ gaiaData+     , trans []+     , mark Point []+     , enc []+     , title label [ TOrient SBottom ]+     ]+++{-|++The actual plot just requires the selection information to be+defined and then added to the plot properties:++<<images/vl/singleselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxB2QykOIFehy6AATwMVH0yBMwVGSkUBOl0D1+GI1H+ZlRIiokugYHgYCMJjMqigmFIyUtUEi6A86BwBo0CMQCXoOqOewS5EwEeOkGK8HIzE1qOCsCoqrhcYSiDD0tFpqxezINuVqIESeqXyLlglVClMv0BgVSqzJxg6pTUCmWBMicgRbxDkDce1AC8u8QE0muwBWV2QHN5xum+OJ5N0PlyBd1hsF34tqjKxQjvboAzwOJhTOr6cb-ByNgAZgXS7CK7AU-XXe6O5t9fzWVUWbRUj31MEoBRT8SA9cgyzOC5zCgElE0nSAJ1gdA6FQRNYgNKA1Q1fQAEdmCQI0mFIUolAgyAb2gks4KbAEkPFOJULlDCsPwHDyDwhdCK7SBSPIsJKOoodT0XRIyEuU0cUUIA Open this visualization in the Vega Editor>++@+let selLabel = "picked"+    sel = 'selection'+            . 'select' selLabel 'Single' []++in toVegaLite (sel [] : 'selectionProperties' selLabel "Select a point")+@++The 'selection' function is used to define the selection, via one or+more applications of the 'select' function. The form of 'select' is+that the selection is named, in this case we use @\"picked\"@, and the+type is given (a 'Single' click), and then options, which in our case+there aren't any, so an empty list is used.++Note that @hvega@ does not track the selection names, and will allow+you to use a name that you have not defined.++-}++singleSelection :: VegaLite+singleSelection =+  let selLabel = "picked"++      sel = selection+              . select selLabel Single []++  in toVegaLite (sel [] : selectionProperties selLabel "Select a point")+++{-|++The only change here is to add a property to the selection - that+is @'Nearest' True@ - which means that the nearest point to the+click will be highlighted.++<<images/vl/nearestselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxB2QykOIFehyxBzWBUap0ODMKiqKDQACeBio+mQJmCoyUigJ0uglvwxGo-zMqJEVEl0DAqu0Gs9RhMZj1kEwpGSLqgkXQHnQOGtGgRiAS9HNRz2CXImFTx0gxXg5B1+mC6oNcOzCUQyeloodWL2ZHdytRAnz1S+tcsEqoUpl+gMCqVpZOMCNJtRUywJjzkFreIccezZoAXqOwMRc-mVwBWIPlys9h05vMF-B8uRBzvd6u-ftUZWKed7dAGeBxMIlg-r49gORsADMO8SPcrzXI8V26c93S7KtZVRPtFVvK0wSgFFVxIUNyEbM4LnMKASTzFdiGXWB0DoVA81ia19RHfQAEdmCQW0mFIUolCQyB31Q+sMN7AEcPFOJ8LlIiSPwMjyAooNDWNWj6NMMImJY2cH0gcsyEuB0cUUIA Open this visualization in the Vega Editor>++@+let selLabel = "picked"+    sel = selection+            . select selLabel Single [ 'Nearest' True ]++in toVegaLite (sel [] : selectionProperties selLabel "Select nearest point")+@++One consequence of this change is that once a point has been selected you+can not remove this (i.e. un-select the point). This is in contrast to+'singleSelection', where clicking on an area with no stars would remove the+previous selection. The 'Clear' property can be added to the list+to define a way to clear the selection.++-}++nearestSelection :: VegaLite+nearestSelection =+  let selLabel = "picked"++      sel = selection+              . select selLabel Single [ Nearest True ]++  in toVegaLite (sel [] : selectionProperties selLabel "Select nearest point")+++{-|++The selection can easily be changed to allow multiple stars+to be selected, using shift-click, by swapping from 'Single' to 'Multi'.++<<images/vl/multiselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxB2GCuUjIMCKsCCmLQMDwMDkeC3Fz4YjQACeBio+iwzEopCUigJ0ugozl1H+ZlRIgVqA1cW5cR0YGg6DAEqoUrARhMy3MUEwpGSrqgkXQHnQOFtGgRiAS9BMlwNu0gCXImCOJ0gxXg5GYZtRwVgVCNcOOBcS2elorzPygZCo5Ho+gEleqXyxe2DUpl+nCKpVauqmu1up7jdLxtNVxTJgrkBHeIcaabyFIAC9q2B7KXy5XTwBWMF7BKIVsTg1litVuh8uSqKBjtuy1FTkqM7qvOOp6kouJ3pA6AGPAcRhA2HYXm+p5yGwADMd6WA+T7tmer5XnQ3TfuKPYhn+k4KkBSqzhqWpgUuu74vmKL4d2vb6Oc8CXCRJIVqexAnrA6B0KgFaxLaUCrqekAAI7MEg9pMKQpRKFBiFsbGHGosiUbinE-FykJIn4GJ5ASSR0n6PJilhMpqm7vuUAPmQuZnjiihAA Open this visualization in the Vega Editor>++@+let selLabel = "this is just a label"+    sel = selection+            . select selLabel 'Multi' []++in toVegaLite (sel [] : selectionProperties selLabel "Shift click to select points")+@++-}++multiSelection :: VegaLite+multiSelection =+  let selLabel = "this is just a label"++      sel = selection+              . select selLabel Multi []++  in toVegaLite (sel [] : selectionProperties selLabel "Shift click to select points")+++{-|++We can take advantage of browser event by using 'On' to define which+event to use, such as mouse movement over points:++<<images/vl/eventselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxB2QykOIFehy6AATwMVH0WGYlFI5igotRWCysXQpVoikUBOl0FGKqo-zMqIAsmaqGBwu6jCYah70GAJVQpWB4GBvaZ9ZBMKRkk6oJF0B50DgrRoEYgEvQTJd8PY9glyJgjidIMV4ORmJrUcFYFRVXDjpAEogs9LDWA8+CyFRyMrUQIK9Uvli9oGpTL9AYFUqGyW1RqrsmTOXICO8Q5U43kKQAF5Vjul8uVugAVlUUGbrYnucPFf3fLk5-FPaDbdlqKniqoystYINBngOIwnrG8yzvOg5DYABmJ9LzCa8DzA498G6J8xzfSdp2-JRNz2FED27Xt9HOeBLjQuJy33Yg91gdA6FQctYitKB533SAAEdmCQG0mFIUolD-SAQIImMiI-AFIxJSi5Rouj8AY8gmKfVj9E47iwl4-j11wptEjIHMOxxRQgA Open this visualization in the Vega Editor>++@+let selLabel = "picked"+    sel = selection+            . select selLabel Multi [ 'On' "mouseover" ]++in toVegaLite (sel [] : selectionProperties selLabel "Move the pointer to select a point")+@++The supported list of events is described in the+<https://vega.github.io/vega/docs/event-streams/#selector Vega Event-Stream Selectors> documentation.++The addition of @Nearest True@ to the list of properties+sent to 'select' would avoid the flickering, as the mouse moves+between the stars.++-}+eventSelection :: VegaLite+eventSelection =+  let selLabel = "picked"++      sel = selection+              . select selLabel Multi [ On "mouseover" ]++  in toVegaLite (sel [] : selectionProperties selLabel "Move the pointer to select a point")+++{-|++The final 'Selection' value is 'Interval',+which lets you drag a rectangle to select the interior points:++<<images/vl/intervalselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxB2NHwLAmYJgUjIMCubT0OXQACeBio+hMNWK8BcikUBOl0FG2qo-zMqI4CGV8DAsCoUqQwVGYGg6DAEo90DARiNyHMUEwpGSDqgkXQHnQOAtGgRiAS9CVRz2CXImGzx0gJvIzANqOC7p1cMLCUQmelovw9nhZCo5C1qIEJeqXyxe0DUplVwVSpVao1sC1YJOMD1ZagU0ViFNkD7eIcKcLyFIAC9583C8XS3QAKzTyy1+tDptF03H-B8uSqKADhuy1HLpfK1XqzVKXHTpA6AGPAcRhFWTZ9reJbznIbAAMznlAl5hNeYDEEe87dM+4ptkGaHyl+Y6-pO-7HJuewouhJDRu2+jnPAlw4SSpr7pAe6wOgdCoKasQWlAur6voACOzBIFaTCkKUSiARB1GtnRqLIhG4pxKxcocVx+A8eQfE4YJ86QKJ4lhJJ0nrhRkC1mQlxNjiihAA Open this visualization in the Vega Editor>++@+let selLabel = "naming is hard"+    sel = selection+            . select selLabel 'Interval' [ ]++in toVegaLite (sel [] : selectionProperties selLabel "Drag a rectangle to select points")+@++-}++intervalSelection :: VegaLite+intervalSelection =+  let selLabel = "naming is hard"++      sel = selection+              . select selLabel Interval [ ]++  in toVegaLite (sel [] : selectionProperties selLabel "Drag a rectangle to select points")+++{-|++The default interval option is to select a rectangle, but it can be restricted -+such as to select all items within a range along a given axis+using 'Encodings':++<<images/vl/intervalselectiony.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxBHPaIeBYEzBMCkZBgaoUchgVzaeh2BGIBL0ZXIOgESAAT0gaig0EtBio+hMNWK8BceLAigJ0ugowN1H+ZlRHAQKug6A1VEl0DARhd6silrj2nd5HggNUUEwpGSwagkXQHnQOG9GkNxuVcssCXImGrezd5GYTtRwVgVGtYL2CUQJulovw9nhZGj+tRAmb1S+WL2EqoUplV0VytV6s15G1utg+u7xxgDtbUCmSoVLlnnvxu3FpAAXkfh-umy26ABWPdQXv9pdDyDPo98nIWbitGC4DrKqIKqeKpqhq0qbjqepKLi3aQOgBjwHEYTWkOs5-u6L74HIbAAMwfpAX5hD+YDEP+dDdMB86LoOx4rogMHrvBW5IZeXqoSiNEkLm5DjmcFzmFAJLug+kD3rA6B0Kg7qxN6dqHvoACOzBIL6TCkKUSioThgmjiJ+jIhJ4pxNJBpyQp+BKeQKnAfajqadpphhHpBmemWNaJGQlxDjiihAA Open this visualization in the Vega Editor>++@+let selLabel = "naming is still hard"+    sel = selection+            . select selLabel Interval [ 'Encodings' [ 'ChY' ] ]++in toVegaLite (sel [] : selectionProperties selLabel "Drag to select points by parallax")+@++We'll come back to further things to do with interval selections+when we get to interactive plots below (see 'bindScales').++-}+++intervalSelectionY :: VegaLite+intervalSelectionY =+  let selLabel = "naming is still hard"++      sel = selection+              . select selLabel Interval [ Encodings [ ChY ] ]++  in toVegaLite (sel [] : selectionProperties selLabel "Drag to select points by parallax")+++-- $intro-selection-transforms+-- Simple selections as described above create sets of selected data marks+-- based directly on what was interacted with by the user. Selection+-- transformations allow us to /project/ that direct selection onto other+-- parts of our dataset.++{-|++For example, we can adjust the visualization to select all stars in the+same cluster, which is useful in this case since the Blanco1 and+IC2391 clusters occupy the same space in the magnitude-parallax+plane.++This is invoked simply by adding the 'Fields' constructor to the select+parameters naming the fields onto which we wish to project our selection.+Additionally, we have set the default selection with 'Empty' so that if+nothing is selected, the selection is empty+(as we have previously seen, without this the default selection is the+entire encoded dataset).++<<images/vl/transformselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxBHPYGUhxPT4ewnNFzWBUap0ODMKhgvZULAGaAATyuiSocOOMFNBitqOQJmCo2tezIVHI9GQdAIkAE5BiNUgylxGkUBOl0FdKpgVH+ZlRIk9VClYHgYCMJmgqjAEtT0HTYDigeqXygmFIyUTUEi6A86BwEY0CMQCXozrllgS5EwXb2xXggYdUGCmvNBu7iQ70tFsY9Xv0AaD5fFKalMv0CqV5igZvtFqwJiHSlxBvFpAAXiPiIPh3QAKy5yAJRAzzexu96uh8uTP-MbnOvyKnoijNja6AGPAcRhOan5Dt++ByGwADMz6vu+QG3ghI7dP+66zrKqLbqB4F7CiYDEAu9D6Oc8CXP+cRDjekDXrA6B0KgQ6xBGe52iOkAAI7MEgUZMKQpRKOecGUSQVaLsRAK7uKTExrJbEcfgXHkDxz77gJwmiWE4mSXiYBkS+iRkJcKo4ooQA Open this visualization in the Vega Editor>++@+let sel = selection+            . select "pick" Single [ 'Fields' [ \"Cluster\" ]+                                   , 'Empty'+                                   , Nearest True+                                   ]++in toVegaLite (sel [] : selectionProperties "pick" "Select a point, select a cluster")+@++-}++-- TODO: why did I call this transformSelection?++transformSelection :: VegaLite+transformSelection =+  let sel = selection+              . select "pick" Single [ Fields [ "Cluster" ]+                                     , Empty+                                     , Nearest True+                                     ]++  in toVegaLite (sel [] : selectionProperties "pick" "Select a point, select a cluster")+++-- TODO: can I think of anything to do with lookupSelection+++-- $intro-selection-binding+-- Selection need not be limited to direct interaction with the+-- visualization marks. We can also /bind/ the selection to other+-- user-interface components.++{-|++New in Vega Lite 4 is the ability to interact with the legend via+the 'BindLegend' option. In this case+selecting on a cluster in the legend will highlight that cluster in+the visualization (but not vice versa). Notice how the legend now+also follows the 'MSelectionCondition' rules (that is, the unselected+items in the image below are also drawn in grey and are partially+transparent).++<<images/vl/legendselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxBHPajYLJeh2SCREzK1EKpXmKDQACeBio+mQJmCox1JFIVHI9GQdAIkAE5BiNUgyjxYEUBOl0HN+GI1H+ZlRImtVClYHgYC1iHoYB5OFUUEwVtM+ki6A86BwXo0CMQCXoprllgS5EwJb2xXgzqNqOCsCoerhx0gCVjYRlldbZGtGqgTpdXyxewl4elos1ZW1YJOMANdagUywJhrkBHHvxu3FpAAXoviNXa3QAKxJtuJIsT2X+yBH5iLvlyc9jqVdqeK2NKXOt9AGeBxGEza3vei5yGwADM57tle75gIeNYPnQ3QvmGb6TlAMbKooP57Ci8GWn2+jnPAlwvnENYHpA+6wOgdCoDWsRerqC76AAjswSA+kwpClEos6QMBBG9ja+jIhaJKUSqNF0fgDHkEx576oa7GcaYYQ8XxHq4ReiBkJc-o4ooQA Open this visualization in the Vega Editor>++@+let sel = selection+          . select "pick" Single [ 'BindLegend'+                                   ('BLField' \"Cluster\")+                                 ]++in toVegaLite (sel [] : selectionProperties "pick" "Select a legend item")+@++-}++legendSelection :: VegaLite+legendSelection =+  let sel = selection+            . select "legend" Single [ BindLegend+                                       (BLField "Cluster")+                                     ]++  in toVegaLite (sel [] : selectionProperties "legend" "Select a legend item")+++{-|++The Elm Vega-Lite walkthrough uses a dataset which has a+column for which a range-slider makes sense. The dataset I'm+using is less rich, and so I am going to use a HTML select+widget - a drop-down list of values - instead. This lets+the user select all stars from a given cluster, and is+introduced with the 'Bind' and 'ISelect' constructors.++The 'InOptions' list is given the values of the Cluster column that+can be selected: I start with a value not in the list (@none@) just to+indicate that no values are selected, and then the list of clusters in+this sub-sample (remembering that 'selectionProperties' applies a+declination cut off). Eagle-eyed readers will note that the cluster+names in this list (the @clusters@ variable) end in spaces: this is+because the input data file has the cluster names stored in an+eight-character field, even though it is a tab-separated file.+This surprised me when I first tried this visualization, and+using the value \"Blanco1\" did not select anything! Isn't working+with data so much fun!++<<images/vl/widgetselection.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoAY3SIyAczrEARvE0BrPbHTNE9OpCNVSeqkvURIWeLDP2ADuikiNCQ7gxM8IYaHsyw5PYAFtDQfsi4APTpCADubHqk0AnMRszINNrBVMFs2ljpHNZ6AEKxZlTpCQBuVHrw6V7I1LAd3b3pjNB9vaTwUvCzAGwAjAtzS3JSk0bkVEvwbIjoUglU8PQ0bNDInaHRUBjYTFEQL1B+3mXPry+QAOJeBnwkEQrEctDC3ygQgAgvxhCJ7CCsGDbpCPH5yAAPRGgmiotGQbhw0Q45F4iHfSBUHgY7FApEou4QRR3FnMsKQAAkyE0Jy8iWSqQy6VG+3yhWKbFI6HSPL5fVFUnIBXanQALGwAFbIHT4yBlHaaaDSxBfdGkcxUOz4UCQqlYPzQACeiJ0rgpHiMQWtYFtBIE5FKQzNBKCfmYISBBqoRvxaKg6EdJuQdAIwLdoSgTXISG0SygqigghkAGYAJz5gtFgQyBZyGQeQuQAByvxraoArPnIMomS82d9FB6oM6-K4o0E9Ds4z8yFRyPQU-g0wGg3je68B0ONDACtObTAqJjI1AAAo7eBlMDRo1geBgTSBwbkhOwUhVE8OdDJdA4bceKptHoScQ0gbRyEwEMPE6eBA3HKBLCoF1hzAnRgONXUbT7Dw5wXexV2fcFsKgG8MNNIE-AtNo7GHDxR3g9MsCCWDID7Ad2TufVSAAL3g4gYLgugOybCp0JNQxIAE5h4LVOQm1I8SKKoq0lH-H5E1MAoXQPKT4LkNgSxEtCCkU31JNg6S6CWeT5xjMj-GUuxFDUjw6TM3CfT+AFM31TRYL4yBeKsOhUFgsohxHJ0x3sABHZgkGNSZjW6NxOO09z3zwiisR8nl-IkoL0BCsKqAimAooYuKEoKJhSBSrcQEUIA Open this visualization in the Vega Editor>++@+let picked = "picked"++    clusters = [ \"none\", \"Blanco1 \", \"IC2391  \", \"IC2602  \", \"NGC2451 \" ]+    sel = selection+            . select picked Single [ Fields [ \"Cluster\" ]+                                   , 'Bind' [ 'ISelect' \"Cluster\" [ 'InOptions' clusters ] ]+                                   , Empty+                                   ]++   conf = configure+            . configuration (Background "beige")++in toVegaLite (conf [] :+               sel [] :+               selectionProperties picked \"Please select a cluster\")+@++Originally this example had the selection working both ways - that is+the HTML widget can be used to select a cluster and clicking on a point on+the visualization updated the HTML widget. However, this no-longer happens+and I don't know whether it is a change in Vega-Lite or I changed+something in the visualization!++Unlike the other plots shown in the tutorial, this is a screen grab+rather than a PNG file created by Vega Embed. The background color was+changed - following the approach used in+'stripPlotWithBackground' - to show where the visualization "ends" and+the HTML select element starts. It also shows the Vega Embed "drop-down"+menu in the top-right corner, namely the three dots in a circle.++-}++widgetSelection :: VegaLite+widgetSelection =+  let picked = "picked"++      clusters = [ "none", "Blanco1 ", "IC2391  ", "IC2602  ", "NGC2451 " ]+      sel = selection+              . select picked Single [ Fields [ "Cluster" ]+                                     , Bind [ ISelect "Cluster" [ InOptions clusters ] ]+                                     , Empty+                                     ]++      conf = configure+               . configuration (Background "beige")++  in toVegaLite (conf [] :+                 sel [] :+                 selectionProperties picked "Please select a cluster")++++{-|++The selection can also be bound to an axis (or both axes, as in this+case), using 'BindScales' (applying it to the 'intervalSelectionY' plot).++<<images/vl/bindscales.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoARAUQH0BJAMIAlAMpgAPGAC0AJgAMkAL4BdADTgoWeLADWdSAAd0pRNEjqIkRtHh1QES81jl9AC2jQDyXAHofCAHc2AHNSaFdmACNmZBoAY3RTKlM2BKwfDnRmYIAhJx0qH1cANypg+B8tZGpYItLyn2sK8tJ4KXg2gDYARk727rkpG0jyKm74NkR0KVcqeHoaNmhkYvMNSwxsJjt1h0NtWJ2HY6gAcS1g-URWSJo1k72hAEF+YRErm7uLB6gDcgAPD5YW60b4PSDcV6iIEg+4-SBUHh-QH4SDXYF3XYQRS7HHY76QAAkyDisy0bg8Xl8PnqE1C4SibFI6B8JLJFVpUnIYUKxQALGwAFbIRJwyCxUZxaDMxBHPYGUhxAr0OyQSImFWoknwUbIcxQZIJegmYJ6-AESAAT31kEBaig0EtBio+hMNWKOqUGkUBOl0FGquo-zMqI4CGCYEwYAAXuh0FgwOEqGB4P8qHrVFBMKRkiGoJF0B540oCYb0MbEJd8PY9glyJg5cdIB7yMwXajgrAqNawbXEsbpaLq1i9mQqORNVABK3ql8R5YJVQpTL9AqlVQVb2m47nVd4yZPSO8Q4fbtxaRo+2wMQW226ABWTOQBKIAcr6vNnV3-B8uRPxfLkOvyKsqSink26AGPAcRhNaH63lechsAAzE+L5vkBN5fle3T-uOS6DrKqJrqBijgXsKLXiQOYTvo5zwJc-5xDqV7EJesDoHQqA6rEPoOk6V6QAAjswSB+kwpClCWZ5wVRY60cRAI2tqAYfuxnH4Nx5C8U+O6CSJYlhBJUnHuRz6JGQVbXjiihAA Open this visualization in the Vega Editor>++@+let picked = "picked"++    sel = selection+            . select picked Interval [ Encodings [ 'ChX', ChY ], 'BindScales' ]++in toVegaLite (sel [] : selectionProperties picked "Drag or zoom the axes")+@++The image here was created after panning and zooming into the data.++-}++bindScales :: VegaLite+bindScales =+  let picked = "picked"++      sel = selection+              . select picked Interval [ Encodings [ ChY, ChX ], BindScales ]++  in toVegaLite (sel [] : selectionProperties picked "Drag or zoom the axes")+++-- $intro-coordinated-views+-- One of the more powerful aspects of selection-based interaction is in+-- coordinating different views – a selection of a data subset is projected+-- onto all other views of the same data.++{-|++The following plot doesn't contain anything new, but allows us to+select a rectangular-range on one plot, and see the same selection+automatically applied to the other plots. This is achieved by+combining the 'repeat' fuction with the 'selection'; this causes the+selection to be projected across all views as it is duplicated.++For this example we use all the clusters, rather than the subset of+Southern ones. One trick I use is to convert the Right Ascension+values (which have a domain of 0 to 360 degrees, and wrap around at+the 0\/360 mark), into their cosine values (remembering to convert to+radians first), and display that instead. This ensures the \"Blanco1\"+cluster members are spatially co-located on this axis - with values+close to 1 - rather than appearing near 0 and 360. This is more to+show things you /can/ do with Vega-Lite, rather than necesarily+things you __should__ do :-)++<<images/vl/coordinatedviews.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMwYHsDuGYA2pAMY4DOASgIKQA0UAIgKID6AkgMJUDKkAXUZkcAGwCuAWwB2hEvFEAPBlADikpAHNBAX3rgoFRKUKgIESCmhJpFAGY5okuQfNZISCoRHU6w0kiipOKiqLDe5BQAFAAmqFIAdLScPLxgAFRgAAocYAD0YACMABwADACUkDquYEI1kBrQANYRAJbQpKLh+m6QcShIpjUW4tCi3gAWKCjwFOh5edZ4CZqtKBPiAEbiFLAdONIosIcJ5JJ5TDjimgBCo02weRMAbrCaSHkaFEfQT6-veX6H3erSQAFokOCAGyFKEQwqlMEDTZdQpIBLSHBgibIGJ7BIoCjPBjDKAOJyoIZuXrwJDQXZU6m9dRabzSKSbPYkpm9ZLcPhsjlcno8iwKZSYSDsySc6Dc0XMdj8-iS6Wy+WiyCwNjiwUyrmkiDVJnG8x6eq7LqkFCtA6mSDwVqkB4xe0oACeiG8rUOe2egSq5t6x3IMR92kwZmpIlEjkZTMg-ok4Ulmjg7o10fI0jDNrtkcN5kgdlasFErslXAk32FhYsltg1ttskljudsFdIs1Hq9qpwkh9AcLprcQejEvcJbLFfccEQlMl5AkMiqwh7KagAEdxDYbQMba9V6TIBnI8XS+X7XPkGhJdB8KuoOvvNvd2tUK1DyOwKax5AACQUKQOIaJM0yzPMeT-OiqzrFsCS2nkQEgR80FgqIayPM8AAsCQAFYUHaIoiNIJYRlg1Q6EAA Open this visualization in the Vega Editor>++@+let enc = encoding+            . position X [ PRepeat Column, PmType Quantitative ]+            . position Y [ PRepeat Row, PmType Quantitative ]+            . color+                [ MSelectionCondition (SelectionName \"picked\")+                  [ MName \"Cluster\", MmType Nominal ]+                  [ MString \"grey\" ]+                ]++    sel = selection+            . select \"picked\" Interval [ ]++    trans = transform+            . calculateAs "cos(datum.RA_ICRS * PI / 180)" "cosRA"++    spec = asSpec+             [ gaiaData+             , trans []+             , mark Circle []+             , enc []+             , sel []+             ]++in toVegaLite+     [ repeat+       [ RowFields [ \"cosRA\", \"DE_ICRS\" ]+       , ColumnFields [ \"plx\", \"Gmag\" ]+       ]+     , specification spec+     ]+@++-}++coordinatedViews :: VegaLite+coordinatedViews =+  let enc = encoding+              . position X [ PRepeat Column, PmType Quantitative ]+              . position Y [ PRepeat Row, PmType Quantitative ]+              . color+                  [ MSelectionCondition (SelectionName "picked")+                    [ MName "Cluster", MmType Nominal ]+                    [ MString "grey" ]+                  ]++      sel = selection+              . select "picked" Interval [ ]++      trans = transform+                . calculateAs "cos(datum.RA_ICRS * PI / 180)" "cosRA"++      spec = asSpec+               [ gaiaData+               , trans []+               , mark Circle []+               , enc []+               , sel []+               ]++  in toVegaLite+       [ repeat+         [ RowFields [ "cosRA", "DE_ICRS" ]+         , ColumnFields [ "plx", "Gmag" ]+         ]+       , specification spec+       ]+++{-|++If the interval selection is bound the the axes with 'BindScales'+then we can zoom and pan the related plots - i.e. changing the+range displayed in one plot will also change the two plots that+it shares an axis with in this two by two arrangement. The conditional+encoding of the 'color' channel has also been removed.++<<images/vl/coordinatedviews2.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMwYHsDuGYA2pAMY4DOASgIKQA0UAIgKID6AkgMJUDKkAXUZkcAGwCuAWwB2hEvFEAPBlADikpAHNBAX3rgoFRKUKgIESCmhJpFAGY5okuQfNZISCoRHU6w0kiipOKiqLDe5BQAFAAmqFIAdLScPLxgAFRgAAocYAD0YACMABwADACUkDquYEI1kBrQANYRAJbQpKLh+m6QcShIpjUW4tCi3gAWKCjwFOh5edZ4CZqtKBPiAEbiFLAdONIosIcJ5JJ5TDjimgBCo02weRMAbrCaSHkaFEfQT6-veX6H3erSQAFokOCAGyFKEQwqlMEDTZdQpIBLSHBgibIGJ7BIoCjPBjDKAOJyoIZuXrwJDQXamSDqLTeaRSTZ7FSQBTKTCQNmSDnQLmwNg81nsznValgaXmPT1XZdUgoVoHRnwVqkB4xRkoACeiG8rUOe2egSqCt6x3IMRN2kwZmpIlEjipMqg5ok4T5mjg+pJHqg5GkdtV6sdpN6dlasFEur5XAk305PSDhjjsBVatkfM12tgurTQcshp9UExkhNFqjstJVudvPcMbjCfccEQlL55AkMiqwgNRr5AEdxDZVQNVa9+6TIAHHZAW-HGR3kGg+dB8P2oIPy5BR+O1qhWtO5RA5Q3IAASCikHEaSbTWbzPL-dGrdZbBJqvK3+8fN8wVENZHmeABmBIACsKHVNMRGkGMHSwaodCAA Open this visualization in the Vega Editor>++The image was captured after panning and zooming in the+\"parallax-RA_ICRS\" plot.++@+let enc = encoding+            . position X [ PRepeat Column, PmType Quantitative ]+            . position Y [ PRepeat Row, PmType Quantitative ]+            . color [ MName \"Cluster\", MmType Nominal ]++    sel = selection+            . select \"picked\" Interval [ BindScales ]++    spec = asSpec+             [ gaiaData+             , mark Circle []+             , enc []+             , sel []+             ]++in toVegaLite+     [ repeat+       [ RowFields [ \"RA_ICRS\", \"DE_ICRS\" ]+       , ColumnFields [ \"plx\", \"Gmag\" ]+       ]+     , specification spec+     ]+@++The \"cosine\" transformation has been removed in comparison to+'coordinatedViews'.++-}++coordinatedViews2 :: VegaLite+coordinatedViews2 =+  let enc = encoding+              . position X [ PRepeat Column, PmType Quantitative ]+              . position Y [ PRepeat Row, PmType Quantitative ]+              . color [ MName "Cluster", MmType Nominal ]++      sel = selection+              . select "picked" Interval [ BindScales ]++      spec = asSpec+               [ gaiaData+               , mark Circle []+               , enc []+               , sel []+               ]++  in toVegaLite+       [ repeat+         [ RowFields [ "RA_ICRS", "DE_ICRS" ]+         , ColumnFields [ "plx", "Gmag" ]+         ]+       , specification spec+       ]+++{-|++The ability to determine the scale of a chart based on a selection is+useful in implementing a common visualization design pattern, that of+'context and focus' (or sometimes referred to as 'overview and detail+on demand'). We can achieve this by setting the scale of one view+based on the selection in another. The detail view is updated whenever+the selected region is changed through interaction:++<<images/vl/contextandfocus.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zULqiYkIIhADaHUKp2ibBYJEIAA5fO9TiYcBoGmQRGwJOtOgw2NBOIQACy+aH3SACYJCeBscQFSDcHB8IiUqSiaAolgUf6QACekAAuikoPB2WR+A0UeZdLACA83oSyfBgg1RvwSfAwLAwABNMD0MQsfhgeAiMAALxEIlkYBRYFaeBEDDRpwZIiZ2oqGygVzQ91OmTYiugDVqsHqMI2RJ+ctQwEghsEIkImXFAilrsw-MFDQAjlhYBIOAg2Po7q6kyHORGsj68H6DpdUnyBUKDpnszK8wWXlV269g0CMnCEdXkajg5gMVi6ag8QTZmdvo7mS6Q6JrWsy97fQ0hng+OZa5BUw2oBFZCjxZBi9P3T3p2vK-66naQxQwwfI9GcLHUPG8Inh519xmsxzRAyQLX9TlgBY2FZMsZXDMAmjwPBOw7MCoFLD1kygG8qygGtUMwJ9xRfGBTVgFFKWJfhSXJMQGmpWkz3PEN-0bQCWxAoVPUee5kPbHl0kgAASJ9ohMBoSHIKhaCsMJ2E4HgmHJagRP4ExqBkpw8A4bRdBxJgACsKApd5IC+b16gjJ4HiAA Open this visualization in the Vega Editor>++@+let sel = selection . select \"brush\" Interval [ Encodings [ ChY ] ]++    encContext = encoding+                   . position X [ PName \"Gmag\", PmType Quantitative, PScale [ SZero False ] ]+                   . position Y [ PName \"plx\", PmType Quantitative ]++    specContext = asSpec [ width 400+                         , height 80+                         , sel []+                         , mark Point []+                         , encContext []+                         , title \"Select a Y range to zoom in below\" []+                         ]++    encDetail = encoding+                  . position X [ PName \"Gmag\"+                               , PmType Quantitative+                               , PScale [ SZero False ]+                               , PAxis [ 'AxNoTitle' ]+                               ]+                  . position Y [ PName \"plx\"+                               , PmType Quantitative+                               , PScale [ SDomain ('DSelection' \"brush\") ]+                               ]+                  . color [ MName \"Cluster\", MmType Nominal ]++  specDetail =+      asSpec [ width 400, mark Point [], encDetail [] ]++in toVegaLite+     [ gaiaData+     , vConcat [ specContext, specDetail ]+     ]+@++Not shown here, but selecting a range of y-values in the top plot+(@specContext@) will cause the second plot (@specDetail@) to zoom+in on that range, as the selection is bound to the y axis of this+plot via 'DSelection'.++-}++contextAndFocus :: VegaLite+contextAndFocus =+  let+    sel =+        selection . select "brush" Interval [ Encodings [ ChY ] ]++    encContext =+        encoding+            . position X [ PName "Gmag", PmType Quantitative, PScale [ SZero False ] ]+            . position Y [ PName "plx", PmType Quantitative ]++    specContext =+        asSpec [ width 400, height 80, sel [], mark Point [], encContext []+               , title "Select a Y range to zoom in below" []+               ]++    encDetail =+        encoding+            . position X+                [ PName "Gmag"+                , PmType Quantitative+                , PScale [ SZero False ]+                , PAxis [ AxNoTitle ]+                ]+            . position Y [ PName "plx"+                         , PmType Quantitative+                         , PScale [ SDomain (DSelection "brush") ]+                         ]+                  . color [ MName "Cluster", MmType Nominal ]++    specDetail =+        asSpec [ width 400, mark Point [], encDetail [] ]++  in+    toVegaLite+      [ gaiaData+      , vConcat [ specContext, specDetail ]+      ]+++-- $intro-crossfilter+-- The final example in this section brings together ideas of view+-- composition and interactive selection with data filtering by implementing+-- /cross-filtering/: the selection of a subset of the data in one+-- view then only displaying that data in the other views.++{-|++Here we show distributions of the four main numeric quantities+in the dataset - position, magnitude, and prallax - using the+@totalEnc@ encoding, and add a second layer which repeats this+data but with a different color (@selectedEnc@), and that is tied to+the interval-selection along the x axis ('ChX').++<<images/vl/crossfilter.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEBOCmAOsCGAXSAuMxIGMD2ANgK4C2AdhmANqQBKAggPoCSAwrQMqQA0UAIgFEW7Lr0gBxEkgDmPKPAIAPSAF0Avt3BQAzohyVQECJAAmqJAa1GoRaAUqQAFihTxt6APQfoSAO4A6aQBLFEciACMibVhofDIUWHj-fBIPPjwiaQAhWwBrWA9HADdYaSQPKW0E6EKSso8zFHKyoKQAWiR2gDYARi6OnoAGNqbwglgepH8yPDbHZBMY-xRtIp4rI0gAMzxoKTRMQ2tN+CRoaMtj44kpWUxIMlJwmPWr6zomNk4HR5Jn6Feb2MCmU91+-0BQMggmE3zBTxemiBxlgjBBPwRAI21jU2LAuJxSM2BCQAE8XpgqHijldIFJoLkHOEzpDrol8CYgmQ7lg8e9QVhtkFYAQTAYYAhkAcoPhiORIBooChSYgHABHIhIeIhVBBEoKolQ0nimTSOBlBIOfBEeJySDK1X3DValA6136glvT2E6l8pU+MjaHZ7ShUbBbIIEari6LjHCuvAUe7haBRRwKtQqQ3XemM5Ms7PvWOweNBRPilNp8XsvCc7naUOQZRZpUq2AOLnVIpIexqDR+yA1us8mlvXCEXbi7vEdv3aSERZkaC1g1+4wC8PC0XiuCIVBWwikCiK+1t9Wa7VNd3t-vIqDGw6QU3m1CzmUZW1iB1vyDOy+6j0-W9IxgJULRbygAASbQcHmKQHGcVx3C8OopmCUIIn8MsPBguDylQtoCBCAoigAFn8AArbRyyJccyAjEdcTUIA Open this visualization in the Vega Editor>++Selecting a small range of parallax values in the fourth plot+highlights the associated data in the other three plots.++@+let sel = selection . select "brush" Interval [ Encodings [ ChX ] ]++    filterTrans = transform . filter ('FSelection' "brush")++    -- borrow a function from Elm+    pQuant = PmType Quantitative++    totalEnc = encoding+                . position X [ PRepeat Column, pQuant ]+                . position Y [ PAggregate Count, pQuant ]++    selectedEnc = totalEnc+                    . color [ MString "goldenrod" ]++in toVegaLite+     [ repeat [ ColumnFields [ \"RA_ICRS\", \"DE_ICRS\", \"Gmag\", \"plx\" ] ]+     , specification $+         asSpec+           [ gaiaData+           , layer+             [ asSpec [ mark Bar [], totalEnc [] ]+             , asSpec [ sel [], filterTrans [], mark Bar [], selectedEnc [] ]+             ]+           ]+     ]+@++-}++crossFilter :: VegaLite+crossFilter =+ let+    sel =+        selection . select "brush" Interval [ Encodings [ ChX ] ]++    filterTrans =+        transform+            . filter (FSelection "brush")++    -- borrow a function from Elm+    pQuant = PmType Quantitative++    totalEnc =+        encoding+            . position X [ PRepeat Column, pQuant ]+            . position Y [ PAggregate Count, pQuant ]++    selectedEnc =+        totalEnc+            . color [ MString "goldenrod" ]++ in+ toVegaLite+    [ repeat [ ColumnFields [ "RA_ICRS", "DE_ICRS", "Gmag", "plx" ] ]+    , specification $+        asSpec+            [ gaiaData+            , layer+                [ asSpec [ mark Bar [], totalEnc [] ]+                , asSpec [ sel [], filterTrans [], mark Bar [], selectedEnc [] ]+                ]+            ]+    ]+++-- $intro-smoothing+-- Vega Lite 4 introduces several ways to \"smooth\" or \"fit\" your+-- data. I've already played around with kernel-density estimation+-- - via the 'density' transform that was used in 'densityParallax' -+-- so now I get to try out 'loess' and 'regression'.++{-|++The 'loess' transform will generate new coordinate pairs for the+independent and dependent values based on an existing pair.+The name stands for+<https://vega.github.io/vega-lite/docs/loess.html locally-estimated scatterplot smoothing>,+and here I use it to look for any possible relationship between the+magnitude and parallax of each star in a cluster. I don't expect+there to really be any (as we've seen before, the distribution+is pretty flat), but it's the data I have to play with in this+tutorial.++<<images/vl/loessexample.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oAKAE3mgFcsA6AEQFEB9AJIBhAEoBlMAD4AvGAAMASjAAyMExbtu-YeLAAeWQBZFkAL4BdADTgozaPDqgIESK1jk6kABbRoAB2RcAHoghAB3DgBzUmgvVgAjVmQaAGN0RGoMjjSsIK50VkiAITcAayogrwA3Kkj4IKx4ZGpYSpq6oLt6utJ4AFp4foA2AEYhgZG5Pvt48ioR+A5EdD6vKnhGGg5oZCrIa2coDGwWRxtDyD94WGSzw4uAcUbIz0R2eJp98-vIEQBBQSiMSvd6fA73Fx+cgADxBWA+tHBEMgvEB4jhCK+EJcVD4UNh+Egb3hn2+EFM3wp5PBkGQfioKTuzm8VFIkR8dAATABWORIqBhUiMWJc3n8yDkeAAT0++AIZLATmxkEasFKnj86FIGSxyqoiDSjG1L3wSuxUDS5EwjhIpCo5EYniE5CSLX2UGgUvpr3QWG18A8ligc0i+sd+De5HIpn5yIJioVyLI9vDUCe8BeseVyBSAaoNoAXjR0HRUAHkjHEz9Pd7CQBHVhIaAxFikGqQKvUztQKVM80uZMOjUw3X9qA5vOF4ul8tUStjlw1-P1xsZFvN9vdqnY7eHef3M3VhAoY44OXdw-myCRWAFPzxXtyyDO12fKzdlxNOgESCwoOQXt3wXYN0CoZBkGHP8PygdJPHTF4tyrIDlVVdVTVpOB0HKAB1IURXwTl-2aW9yk8WZ4BSdV-yXTxyG1fN92RfVDWNPtlXjYhB1TX93RgL1lygBsm3XNt83-eBoVICCI1YKNGOVR9FVtFNPF7aj+M8IS13sDcxKgCSpLoSNoyrXdnDM8wbH3SAABIczWRpPB8fxAhCdpFmiWIEg4Uh0CCeyqEaIJ3L6OjqGCwwOAAK2QWCaUtdgUC5GkyxSKhoBtLinRdZowQ9DTCWWP1EADMx4vSMgTUVClTCAA Open this visualization in the Vega Editor>++@+let simplify = transform+               . filter (FExpr \"(datum.DE_ICRS >= 0) & (datum.DE_ICRS <= 40)\")++    rawEnc = encoding+            . position X [ PName \"Gmag\"+                         , PmType Quantitative+                         , PScale [ SZero False ]+                         ]+            . position Y [ PName \"plx\"+                         , PmType Quantitative+                         , PScale [ SZero False ]+                         ]+            . color [ MName \"Cluster\"+                    , MmType Nominal+                    , MLegend []+                    ]++    rawLayer = asSpec [ rawEnc [], mark Point [] ]++    trans = transform+            . 'loess' \"plx\" \"Gmag\" [ 'LsAs' \"x\" \"y\"+                                 , 'LsGroupBy' [ \"Cluster\" ] ]++    trendAx pos lbl = position pos [ PName lbl+                                   , PmType Quantitative+                                   , PAxis []+                                   ]+    trendEnc = encoding+               . trendAx X \"x\"+               . trendAx Y \"y\"++    trendLayer = asSpec [ trans []+                        , trendEnc []+                        , mark Line [ MStroke \"black\"+                                    , MStrokeWidth 2+                                    ]+                        ]++    frameSpec = asSpec [ width 250+                       , height 250+                       , layer [ rawLayer, trendLayer ] ]++in toVegaLite+     [ gaiaData+     , simplify []+     , columns 2+     , facetFlow [ FName \"Cluster\", FmType Nominal ]+     , specification frameSpec+     ]+@++The data is filtered to select only four clusters, ensuring that+the two closest (i.e. they have the largest parallax values) are+included as they are likely to be the most-interesting to look+at (because of the spread of parallax values).++The 'LsGroupBy' option is used to ensure the calculation is done+per cluster, and then multiple layers are used to compare the+raw with the "smoothed" data in a faceted display.++-}++loessExample :: VegaLite+loessExample =+  let simplify = transform+                 . filter (FExpr "(datum.DE_ICRS >= 0) & (datum.DE_ICRS <= 40)")++      rawEnc = encoding+              . position X [ PName "Gmag"+                           , PmType Quantitative+                           , PScale [ SZero False ]+                           ]+              . position Y [ PName "plx"+                           , PmType Quantitative+                           , PScale [ SZero False ]+                           ]+              . color [ MName "Cluster"+                      , MmType Nominal+                      , MLegend []+                      ]++      rawLayer = asSpec [ rawEnc [], mark Point [] ]++      trans = transform+              . loess "plx" "Gmag" [ LsAs "x" "y"+                                   , LsGroupBy [ "Cluster" ] ]++      trendAx pos lbl = position pos [ PName lbl+                                     , PmType Quantitative+                                     , PAxis []+                                     ]+      trendEnc = encoding+                 . trendAx X "x"+                 . trendAx Y "y"++      trendLayer = asSpec [ trans []+                          , trendEnc []+                          , mark Line [ MStroke "black"+                                      , MStrokeWidth 2+                                      ]+                          ]++      frameSpec = asSpec [ width 250+                         , height 250+                         , layer [ rawLayer, trendLayer ] ]++  in toVegaLite+       [ gaiaData+       , simplify []+       , columns 2+       , facetFlow [ FName "Cluster", FmType Nominal ]+       , specification frameSpec+       ]+++{-|++This is the same data as 'loessExample', but using a linear+regression model to try and explain the data. Practically,+the only things that have changed are switching from+'loess' to 'regression', and displaying all the data in+a single visualization.++<<images/vl/regressionexample.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oAKAE3mgFcsA6AEQFEB9AJIBhAEoBlMAD4AvGAAMASjAAyMExbtu-YeLAAeWQBZFkAL4BdADTgoACyqkA5reh0AzHLnWIkZtHh0oBA+rLDkdJAu0AAOyLgA9PEIAO4cjqTQtqwARqzINADG6IjUJRxFWPFc6KyOAEKhANZU8bYAblSO8PFY8MjUsK0dXfF+3V2k8AC08NMAbACMczMLclP+2eRUC-AciOhT9vCMNBzQyG2Q3sEkmL2u+EHBPtHwsPmBNs8+AOK9jhFEOxsjQrl9vpARABBQSiMSA4Gg67fKDRcgADwRWBBtGREN4sPEWJxYJRPiofDRmPwkCB2NB4IgpnBzKZ10gyVIjEy7k87IAJMgCvZehEorEEvFhrt0pkchxSOh4kKRd1pVNyBkWm1DBwAFbIYqkqDkeAAT1B+AI4Kez0gvVgjQi0XQpBKxrtVEQRUYboBj0ZNyK5EwgRIpCo5EYESE5DyAyuUGgZuiVEB6Cwbvg4VMeLt1LAtrJ4cj0Zpf3gALzEKF2bTj0gAC8aOg6Khs-lc4G7cnUxEAI6sJDQDIsUgdSDdsBdslQM1hsil50YxOQWtbMPN2Ct-Dt8idyxJlP1qCD4ejkcT1nfa9sm2BmAIFAYbB0a2zosoyCObesaLZecrUgWN41BKwpx8Po30gTFD0gedwNnHxYE6FDkGQRVEGXWCIKgI1y3+SdZ1vYJEIhB0nQbfpt2aAB1LkeXwAAmODqPQZoIk2eACidODexPSBNUQNMZwhL0fT9T5Z0gYNQwbRcoxjON+iRI8+xpfZM0QbMzGrHwC2IBSyygWC1IEs8Sgvcc0zg+B0VIZA6CBchyFEr9AMLEtFJpec+OPAch0s-xLxsqA7IcpzWBckimRZGwyJk4oyH9QtmVMIA Open this visualization in the Vega Editor>++@+let simplify = transform+               . filter (FExpr \"(datum.DE_ICRS >= 0) & (datum.DE_ICRS <= 40)\")++    rawAx pos lbl = position pos [ PName lbl+                                 , PmType Quantitative+                                 , PScale [ SZero False ]+                                 ]+    cluster = color [ MName \"Cluster\"+                    , MmType Nominal+                    ]++    rawEnc = encoding+             . rawAx X \"Gmag\"+             . rawAx Y \"plx\"+             . cluster++    rawLayer = asSpec [ rawEnc [], mark Point [] ]++    trans = transform+            . 'regression' \"plx\" \"Gmag\" [ 'RgAs' \"x\" \"y\"+                                      , 'RgGroupBy' [ \"Cluster\" ] ]++    trendAx pos lbl = position pos [ PName lbl+                                   , PmType Quantitative+                                   , PAxis []+                                   ]+    trendEnc = encoding+               . trendAx X \"x\"+               . trendAx Y \"y\"+               . cluster++    trendLayer = asSpec [ trans []+                        , trendEnc []+                        , mark Line [ MStroke \"black\"+                                    , MStrokeWidth 2+                                    ]+                        ]++in toVegaLite+     [ width 300+     , height 300+     , gaiaData+     , simplify []+     , layer [ rawLayer, trendLayer ]+     ]+@++In this example I used the default method - 'RgLinear' - but other+options are possible (set with the 'RgMethod' option).++-}++regressionExample :: VegaLite+regressionExample =+  let simplify = transform+                 . filter (FExpr "(datum.DE_ICRS >= 0) & (datum.DE_ICRS <= 40)")++      rawAx pos lbl = position pos [ PName lbl+                                   , PmType Quantitative+                                   , PScale [ SZero False ]+                                   ]+      cluster = color [ MName "Cluster"+                      , MmType Nominal+                      ]++      rawEnc = encoding+               . rawAx X "Gmag"+               . rawAx Y "plx"+               . cluster++      rawLayer = asSpec [ rawEnc [], mark Point [] ]++      trans = transform+              . regression "plx" "Gmag" [ RgAs "x" "y"+                                        , RgGroupBy [ "Cluster" ] ]++      trendAx pos lbl = position pos [ PName lbl+                                     , PmType Quantitative+                                     , PAxis []+                                     ]+      trendEnc = encoding+                 . trendAx X "x"+                 . trendAx Y "y"+                 . cluster++      trendLayer = asSpec [ trans []+                          , trendEnc []+                          , mark Line [ MStroke "black"+                                      , MStrokeWidth 2+                                      ]+                          ]++  in toVegaLite+       [ width 300+       , height 300+       , gaiaData+       , simplify []+       , layer [ rawLayer, trendLayer ]+       ]+++-- XXX TODO: add an example showing R2 in plot title+++-- $intro-error+-- Here we dive into some of the ways for representing the spread+-- of a value, focussing on the \"error\" of a variable.++{-|+We have already seen "error bars" in the 'layeredDiversion' plot, where+the 'Rule' type was used to draw a line between the 'Y' and 'Y2'+encodings. In that example the two positions were calculated \"on the+fly\" by Vega-Lite (using the 'Min' and 'Max' aggregation operations).+In this example I use the data to calculate the display range,+namely @plx - e_plx@ to @plx + e_plx@. These are mapped to the+'X' and 'X2' channels (not because it makes a better visualization,+but just to show you can create lines along the x axis), and a+small-multiples approach is used to separate out the clusters, but+only after a filter designed to select the two clusters - with the+\"most interesting\" data for this plot - has been applied.++<<images/vl/errormanual.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxhJUBLAG2gFNY8oATeaAVywDoBhKt5OrAIAGALpgAvBLABybjLAAfRWBbsuvfoJHipsgBIzIAXwA0xCGXjJGkAA5UAHgH0q6SKagBjeFS9sqVlpbNQ5OB0cwAFpVVjDaZwiTcxJSSGtbCOcACwoPb19-QLoQuK4IsABqWPVOBKTjYlEUqCx4WABrW1gA4JbINXhGUFTINlgqW2zoaDtkXAB6BYQAd04AcwpobLYAI356L3REOhPOI6wFgBF0NnWAIXGO2gXsgDdadfgFtoF6V4+XwWgwWXwo8Ci8AhADYAIzQyGw4RRaDwXZUWiw+CcRDoKLZWjwJj0TjQZBvDwWKAYbCsYZUiD2drIYL4EapEiQADibXWtkQHF29EpHM5ACUAILOACS3DFAGV+YLhS1RfYnEqsEKGKqOZArgBRGVyxX4SACrUqhmc+oas0W7WQa2NVIusBmYiQAAkyC8BLaUxmc0WC0B2M22z2nAo6AWvv93zDUSoWxebwALJwAFbIY4iqAsjFeaAxxDDewULzPJjl3YURA1s2+3y0GyeGAATzsrKg9cEb18Jg9jNoiCOTHrfLZVMgjgATOXKLQqI2oFlcskZ456WqlyvMk5XO5dYzmxjywAvejufCoXws4d66BdnuQACObCQJdRJY++dG8COBQNhsjAWznmadjtL4gSRAAFL8ACUJhUo+jJHHwWBlqBe6rpAmh-DqUDPt2-LoFg9aDmhUAdouFDLnhPLwHy7Yka+H5flsrAUH+bqPpARyIJQU6kI0xhAA Open this visualization in the Vega Editor>++@+let trans = transform+              . filter (FExpr \"datum.Cluster[0] == \'C\' || datum.Cluster[0] == \'H\'\")+              . calculateAs \"datum.plx - datum.e_plx\" \"plx_lo\"+              . calculateAs \"datum.plx + datum.e_plx\" \"plx_hi\"++    errorEnc = encoding+                 . position X [ PName \"plx_lo\"+                              , PmType Quantitative+                              , PScale [SZero False]+                              , PAxis [ AxTitle "parallax (mas)" ]+                              ]+                 . position 'X2' [ PName \"plx_hi\" ]+                 . position Y [ PName \"Gmag\", PmType Quantitative ]+                 . column [ FName \"Cluster\", FmType Nominal ]++    sel = selection+            . select "picked" Interval [ BindScales ]++in toVegaLite [ gaiaData+              , trans []+              , errorEnc []+              , mark Rule []+              , sel []+              ]+@++For the interested reader, it was the calculation of the @\"plx_hi\"@+column that lead me to the discovery that the columns were being+read in as a string, and the introduction of the 'Parse' option+to 'gaiaData'.++As can be seen, the @e_plx@ terms are generally very small. This is+good for anyone using the data, as we want precise measurements, but+makes it harder for me to come up with meaningful visualizations! I+have taken advantage of the 'BindScales' interaction to zoom in on+a subset of stars which show larger parallax errors:++<<images/vl/errormanual-zoomed.png>>++-}++errorManual :: VegaLite+errorManual =+  let trans = transform+                . filter (FExpr "datum.Cluster[0] == 'C' || datum.Cluster[0] == 'H'")+                . calculateAs "datum.plx - datum.e_plx" "plx_lo"+                . calculateAs "datum.plx + datum.e_plx" "plx_hi"++      errorEnc = encoding+                  . position X [ PName "plx_lo"+                               , PmType Quantitative+                               , PScale [SZero False]+                               , PAxis [ AxTitle "parallax (mas)" ]+                               ]+                  . position X2 [ PName "plx_hi" ]+                  . position Y [ PName "Gmag", PmType Quantitative ]+                  . column [ FName "Cluster", FmType Nominal ]++      sel = selection+              . select "picked" Interval [ BindScales ]++  in toVegaLite [ gaiaData+                , trans []+                , errorEnc []+                , mark Rule []+                , sel []+                ]++{-|++Alternatively, I could have made life simpler for myself and used+the 'ErrorBar' (or 'ErrorBand') mark type, together with 'XError'+(or 'YError') to indicate that the channel gives the offset from+the central value. For this visualization I restrict to a single+cluster (since I now know there's only one in this sample which+begins with @C@), but retain the 'column' encoding as a means+to getting a useful title. I've also switched things so that the+errors are back along the y axis.++<<images/vl/errorauto.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJUBLAG2gFNY8oATeaAVywDoBhc55a2AgAwBdMAF5RYAOQdJkAL5CANOChZ4sANZ1INWJgBG6yMoiRG0eHVARTzWOW0ALaNAAOyXAHpPCAO5sAc1JoR2Z9HhoAY3REali2aKxPABF0ZgCAITsNKk9HADcqAPhPNV4aPMLiz3MS4tJ4AFp4JoA2AEZW5vaBRot9cip2+DZEdEbHKnh6GjZoZHzjFVMMbCYrZZtIV3VkKg2bQ6gAcTUA7URWfRolo62AJQBBAH0ASQ57gGULq5uTO6grnIAA8flhrrR-ndIMkAKJvD7ffCQS7gv6bQ46Z5A0HI1EQyAYsByTYkiByf6QAAkyEikzUThc7i8niqIyCITCbFI6E8tPpJTZjXIwVy+QALGwAFbIGK3KBURDReikRDnfDWLYAT1hsD0tA1JFIVHI9G0VGxIPkUKguLAxDIJrNyNO8HOiig0C1rn2yIAjswkNBgkxSIVrZtINFuFhEFYjU7tFweHxjJ7vb6oGMsKr4A4KZGtQcjgnTdocfLMbS85niAAvGjoOioPN7AvQr0+7QBoMh4Phm2meDA0jIePB6CDcvqPPkYdgAAUZQAlPJSSp21BoogyOr7SS5EA Open this visualization in the Vega Editor>++@+let trans = transform+              . filter (FExpr \"datum.Cluster[0] == \'C\'\")++    errorEnc = encoding+                . position Y [ PName \"plx\"+                             , PmType Quantitative+                             , PScale [SZero False]+                             , PAxis [ AxTitle \"parallax (mas)\" ]+                             ]+                . position 'YError' [ PName \"e_plx\" ]+                . position X [ PName \"Gmag\", PmType Quantitative ]+                . column [ FName \"Cluster\", FmType Nominal ]++in toVegaLite [ gaiaData+              , trans []+              , errorEnc []+              , mark 'ErrorBar' []+              ]+@+-}++errorAuto :: VegaLite+errorAuto =+  let trans = transform+                . filter (FExpr "datum.Cluster[0] == 'C'")++      errorEnc = encoding+                  . position Y [ PName "plx"+                               , PmType Quantitative+                               , PScale [SZero False]+                               , PAxis [ AxTitle "parallax (mas)" ]+                               ]+                  . position YError [ PName "e_plx" ]+                  . position X [ PName "Gmag", PmType Quantitative ]+                  . column [ FName "Cluster", FmType Nominal ]++  in toVegaLite [ gaiaData+                , trans []+                , errorEnc []+                , mark ErrorBar []+                ]++++{-|++In this plot the error range is calculated by Vega-Lite,+and is taken from the standard deviation of the @Gmag@ field+('StdDev'). The 'MTicks' and 'MRule' constructors are used to+color the different parts of the error bars. Since the error bar+does not reference the central value, a separate layer is used+to add a square symbol ('SymSquare') at the average ('Mean')+value of the distribution.++<<images/vl/errorbars.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFACYCGKpGYoEEkArgE4A2VMKKADgM7oD0fRqQDuAOkTwU0egCN63WIwDGAewB2KWBtGqAtnwAiK+ogBCTANaw+0AG6xEpPrtLdNjG-cd8yFPo-hSAFpSYIA2AEYwkIicIIoZZlgI0lE1FSC4UmJFURRuW0hCWigAMxVGFzRMGhKoTlJGBSpauqgAcRdENjV6XRlFIqI2yAAlAEEAfQBJAGFRgGUevoHGIba6TmYAD2X+weKNyAMAURn5pcxIXv21w5HYSa3dq5vVyGHaAF9Pn4gvw6QYTwYhSKi4AhESAAEm4SjgLjYqC4vAEXlSEikslE8BUfDhCKc6KCzEk1lsABZRAArbjqdZQZikACeg0wAG1Pq1aJAXIwLC1PiVIIx6EkWpBVMwKmxNKRWAChTzYNtNBo2G4coV7nVIChmZxYGxFIwKjJGgyRih4EoLNwJVKZVdOEwtka-nVFQ81KpiPA1N0akq6MyJaV4LBmMQ2J1SN18FA4fKjTVIAAvRQqKileUKAFQfWGtgAR3opA0knI8HskA9JTrYC9tG5dD5AtT3HgGaoACYCInoKQi1duKXGkaE3qDSn6ip-Wgm8KtL7-YHqMGoKHU+HI9GrrH41A44hGA5yDPebBy0UC9OS2WKxRrTWG-9fkQALqA5cqP0BiUvNQkA7lGbCzMw8juDeU7DlA6S6P68q1k2krqOGa7AD8XxAA Open this visualization in the Vega Editor>++@+let cluster = position X [ PName \"Cluster\", PmType Nominal ]++    barOpts = [ 'MExtent' 'StdDev'+              , 'MTicks' [ 'MColor' \"purple\" ]+              , 'MRule' [ MColor \"teal\" ]+              ]+    range = [ mark ErrorBar barOpts+            , encoding+                . position Y [ PName \"Gmag\"+                             , PmType Quantitative+                             , PScale [ SZero False ]+                             ]+                $ []+            ]++    center = [ mark Point [ 'MShape' 'SymSquare', 'MSize' 20 ]+             , encoding+                 . position Y [ PName \"Gmag\"+                              , PmType Quantitative+                              , PmType 'Mean'+                              ]+                 $ []+             ]++in toVegaLite+      [ gaiaData+      , encoding (cluster [])+      , layer (map asSpec [ range, center ])+      , width 300+      , height 300+      ]+@++-}++errorBars :: VegaLite+errorBars =+  let cluster = position X [ PName "Cluster", PmType Nominal ]++      barOpts = [ MExtent StdDev+                , MTicks [ MColor "purple" ]+                , MRule [ MColor "teal" ]+                ]+      range = [ mark ErrorBar barOpts+              , encoding+                  . position Y [ PName "Gmag"+                               , PmType Quantitative+                               , PScale [ SZero False ]+                               ]+                  $ []+              ]++      point = [ mark Point [ MShape SymSquare, MSize 20 ]+              , encoding+                  . position Y [ PName "Gmag"+                               , PmType Quantitative+                               , PAggregate Mean+                               ]+                  $ []+              ]++  in toVegaLite+      [ gaiaData+      , encoding (cluster [])+      , layer (map asSpec [ range, point ])+      , width 300+      , height 300+      ]+++{-|+The next plot shows the 'ErrorBand' mark, which fills the area between+the chosen range with a color, and optional borders. Here the+blue band shows the calculated standard deviation - as used in+'errorBars' - and the gray band with borders shows the inter-quartile+range. On top of these are drawn the median (blue) and median (green+dashed) lines.++<<images/vl/errorband.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFACYCGKpGYoEEkArgE4A2VMKKADgM7oD0fRqQDuAOkTwU0egCN63WIwDGAewB2KWBtGqAtnwAiK+ogBCTANaw+0AG6xEpPrtLdNjG-cd8yFPo-hSAFpSYIA2AEYwkIicIIoZZlgI0lE1FSC4UmJFURRuW0hCWigAMxVGFzRMGhKoTlJGBSpauqgAcRdENjV6XRlFIqI2yAAlAEEAfQBJAGFRgGUevoHGIba6TmYAD2X+weKNyAMAURn5pcxIXv21w5HYSa3dq5vVyGHaAF9Pn4gvw6QYTwYhSKi4AhESAAEm4SjgLjYqC4vAEXlSEikslE8BUfDhCKc6KCzEk1lsABZRAArbjqdZQFCSJJsWYqXQNRjwNSIMBCHmwbgMyDMUgAT0GmAA2p9WrRIC5GBYWpBYNtNBo2G4coV8IyxZxYGxFIwKjJSGpiJAAZ86FpVMRud0arb5WKVaV4LBmFarp1SN09ZA4aQWTVIAAvRQqKilUMKAH6w1sACO9AtTIoTPs1tdf2+92oroVjWVLo2UBkFRyTRVblNVgMrmgVClYT1ACYALo2iuQVTMCpsRBCd2Fkqq9VaapQeApu6uugoA1Gq4ms0Wq158dQe0qR08lqLqDu8Oe72+jpdIpQENh6iR6Ox+OwROQZfJq5pjOScjwHP5iUgFgL2tBynQipllApJqEaO6qmoDpOkefankWFZ0OePpsP6gbHnQd6rg+Uams+zAJjuE4BiODjkERCqwI6FoMn2H70d+Gi-tmRrHsB-y-IW4FQJBKoDkOVw0VoN7BigDawE23AttK7ZgB2eoUp2XZBmxbAwUaoETnuB7OuhRxoUJE5YZekC4SxRyESqJExpgcbka+lHytRjC0ZobC6LAzEeUuK6pumnFZv+PEVnxIG-EQWlQkZyHhi8D5WayzDyO40k6a87LcqG1qgf26ieiZwA-F8QA Open this visualization in the Vega Editor>++@+let posY extra = position Y ([ PName \"Gmag\"+                             , PmType Quantitative+                             , PScale [ SZero False ]+                             ] ++ extra) []++    bands = [ [ encoding (posY [])+              , mark 'ErrorBand' [ MExtent StdDev ]+              ]+            , [ encoding (posY [])+              , mark ErrorBand [ MExtent 'Iqr'+                               , 'MBorders' [ 'MStrokeDash' [ 6, 2 ] ]+                               , MColor "gray"+                               ]+              ]+            , [ encoding (posY [ PAggregate Median ])+              , mark Line []+              ]+            , [ encoding (posY [ PAggregate Mean ])+              , mark Line [ MColor \"green\"+                          , MStrokeDash [ 6, 2, 4, 2 ]+                          ]+              ]+            ]++in toVegaLite+    [ gaiaData+    , encoding (position X [ PName \"Cluster\", PmType Nominal ] [])+    , layer (map asSpec bands)+    , width 300+    , height 300+    , title "Comparing ranges" []+    ]+@++Note that I don't think this is a good visualization+for this /particular/ dataset, since it implies there's a+connection or correlation between clusters, as given by the+x-axis ordering, but the aim here is to show how to use @hvega@+rather than creating sensible plots!++-}++errorBand :: VegaLite+errorBand =+  let posY extra = position Y ([ PName "Gmag"+                               , PmType Quantitative+                               , PScale [ SZero False ]+                               ] ++ extra) []++      bands = [ [ encoding (posY [])+                , mark ErrorBand [ MExtent StdDev ]+                ]+              , [ encoding (posY [])+                , mark ErrorBand [ MExtent Iqr+                                 , MBorders [ MStrokeDash [ 6, 2 ] ]+                                 , MColor "gray"+                                 ]+                ]+              , [ encoding (posY [ PAggregate Median ])+                , mark Line []+                ]+              , [ encoding (posY [ PAggregate Mean ])+                , mark Line [ MColor "green"+                            , MStrokeDash [ 6, 2, 4, 2 ]+                            ]+                ]+              ]++  in toVegaLite+      [ gaiaData+      , encoding (position X [ PName "Cluster", PmType Nominal ] [])+      , layer (map asSpec bands)+      , width 300+      , height 300+      , title "Comparing ranges" []+      ]+++{-|++An alternative visualization of a distribution is the \"box and+whiskers\" plot, which can be achieved in @hvega@ with the+'Boxplot' mark. The example below shows the default settings, but+the various components can be controlled with 'MBox', 'MMedian',+'MOutliers', and 'MTicks'.++<<images/vl/errorbox.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMBmADDgNOFALYCGATgNYZQBGA9gB4AOANvWoRJACakqkaoCNwCu5VjRgoUzAM7oA9IvKkA7gDpE8FNFG1Rc2OQDG9AHYpYljWeKKAIvVGIAQuMqxF0AG6xEpIpkclbk3n4BinwCigHwpAC0pIkAbACMKUlpOAkCtKywaaQa5vQJcKQ8xhoocj6QXCKQAGb05GRomMIi3MwURkJEPdwA4mSIUuaixLTGDUPDkABKAIIA+gCSAMJLAMqT07Pk88NNbIwHM3ONp5AOAKKbO-uYkFNXxzeLsGvnl0eQBYQAC+C1BIMakDU8B4uhouAIREgABI5CY4GQpKhZAplBFitpdPoNPB6Io0RjAviEqwdF4fAAWDQAKzkFhOUGsZh48HMEy6C0gFy6LXgsFYPCkW1YhlCDSgKAAnsxYJN6MReaRJMCvpBFUJReLJa8xqQJvgFcrVa8AI6iUiWHT8eB+SDgsA6pFmczNJBCUHAoA Open this visualization in the Vega Editor>++@+toVegaLite+    [ gaiaData+    , encoding+        . position X [ PName \"Cluster\", PmType Nominal ]+        . position Y [ PName \"Gmag\", PmType Quantitative ]+        $ []+    , mark 'Boxplot' []+    , width 300+    , height 300+    ]+@++The 'Boxplot' option supports two different \"ranges\":++ * the default is the Tukey Box plot, where the whiskers span+   a range @Q1 - k * IQR@ to @Q3 + k * IQR@, @IQR = Q3 - Q1@,+   @Q1@ and @Q3@ are the lower and upper inter-quartile values+   (so 25 and 75 per cent of the distribution), and @k@+   defaults to 1.5 but can be changed with 'IqrScale';++ * or 'ExRange', which uses the full range of the data (i.e.+   minimum to maximum values).++-}++errorBox :: VegaLite+errorBox =+  toVegaLite+      [ gaiaData+      , encoding+          . position X [ PName "Cluster", PmType Nominal ]+          . position Y [ PName "Gmag", PmType Quantitative ]+          $ []+      , mark Boxplot []+      , width 300+      , height 300+      ]+++{-|++Here I combine 'errorBox' with 'smallMultiples2' so we can compare+the distribution (from the histogram) with that from the box plot.++<<images/vl/comparingerrors.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zUBRk-EIVp3iwAE82qgANr3QqzSAmHAaBrcUrrDZnMSiaBsMT1VAQpGiPA5ApZNj8PDQBpDPB8cypKDwAFfCYiWTo2AEFJQYIsKSk1BNPB4N73U5XNCE4ncqC1WD1NmQbjowjwHBYfgy2n0g4ARywsAkHAQbH0kAFGwyAN+JoyUpYOAMCH4DVEWAkiItNLp9s12t1iHgBvt71dkFgCzYFAJvvgwQaADkjjgwCJMmBRogykbBRgXhss0VjVVsadobCsRnMLJ+GidQTcfiDkFYEJYXmTbKRMLgJAzDgRFoGgwiBx7c2kcpI0S06hMiyBAGkWqPVBuG35iJ8hnh6cpKj0Zi0KWoDW1ljRSSyRSzNM3eqoBEmWIWdTIByuYRefzZ5D2yfxZBJdKrwukBajqEb6oaG6dGax66CyyqEAAHL4OZVMhrwdAAuukeaQAAJBQQjRCYDQkOQVC0FYYTsJwPBMGwIjUPhhFGBRTh4IO1C6AALEwABWFDiIikC4s0YhhqgADM7xZA2-D5MemREqeBzkpSl6QPODJ3g+2GiGICm7sATwPEAA Open this visualization in the Vega Editor>++@+let histEnc = encoding+                . position X [ PName \"Gmag\", PmType Quantitative, PBin [] ]+                . position Y yAxis+                . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]++    errEnc = encoding+               . position X [ PName \"Gmag\", PmType Quantitative ]+               . position Y [ 'PNumber' 80 ]+               . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]++    yAxis = [ PAggregate Count+            , PmType Quantitative+            , PAxis [ AxTitle \"Number of Stars\" ]+            ]++    boxOpts = [ 'MMedian' [ MColor \"black\" ]+              , 'MBox' [ MStroke \"white\" ]+              , 'MNoOutliers'+              ]++    histSpec = asSpec [ mark Bar [], histEnc [] ]+    errSpec = asSpec [ mark Boxplot boxOpts, errEnc [] ]++    combinedSpec = asSpec [ layer [ histSpec, errSpec ] ]++in toVegaLite+    [ gaiaData+    , columns 3+    , facetFlow [ FName \"Cluster\", FmType Nominal ]+    , specification combinedSpec+    ]+@++The main additions here are the configuration of the box plot - with+'MMedian', 'MBox' (used to ensure the box is visually distinct from+the bar for the Pleiades cluster, where they overlap), and 'MNoOutliers'+(to turn off the display of the outliers) - and the use of 'PNumber'+to define the location on the y axis of the boxplot visualization.+Note that 'PNumber' is defined in pixel units, with 0 being the+top of the visualization and 80 was found by trial and error.++-}++comparingErrors :: VegaLite+comparingErrors =+ let histEnc = encoding+                . position X [ PName "Gmag", PmType Quantitative, PBin [] ]+                . position Y yAxis+                . color [ MName "Cluster", MmType Nominal, MLegend [] ]++     errEnc = encoding+                . position X [ PName "Gmag", PmType Quantitative ]+                . position Y [ PNumber 80 ]+                . color [ MName "Cluster", MmType Nominal, MLegend [] ]++     yAxis = [ PAggregate Count+             , PmType Quantitative+             , PAxis [ AxTitle "Number of Stars" ]+             ]++     boxOpts = [ MMedian [ MColor "black" ]+               , MBox [ MStroke "white" ]+               , MNoOutliers+               ]++     histSpec = asSpec [ mark Bar [], histEnc [] ]+     errSpec = asSpec [ mark Boxplot boxOpts, errEnc [] ]++     combinedSpec = asSpec [ layer [ histSpec, errSpec ] ]++ in toVegaLite+     [ gaiaData+     , columns 3+     , facetFlow [ FName "Cluster", FmType Nominal ]+     , specification combinedSpec+     ]+++-- $intro-dashboard+-- In the following visualization I try to combine as many of the+-- concepts we have explored in this tutorial into one. There are+-- layers, combined visualizations, and a+-- selection that ties the different plots together! How much more+-- could you want?++{-|++This is based on the+<https://vega.github.io/vega-lite/examples/concat_marginal_histograms.html Marginal Histogram>+example from the Vega-Lite+<https://vega.github.io/vega-lite/examples/ Example Gallery>.+There is very-little new in this plot, in that pretty-much everything+has been shown before. However, there are some interesting wrinkles,+such as++  * combining multiple plots, in this case the \"top\" area - which is+    a histogram on top of a plot which is itself a \"map\" and+    a histogram - and \"bottom" area - which is just a point plot -+    requires judicious use of 'asSpec';++  * selection works in __both__ the main plots - the \"map\" and \"point\"+    plots - to highlight all stars in the same cluster, and I was+    pleasantly surprised to find out I could just use the same selection+    specification (@selCluster@) in both (hopefully I am not just+    enjoying a hole in the Vega-Lite specification);++  * I have been perhaps too defensive in defining the Right Ascension+    and Declination axes in the relevant plots, as I want to make sure+    the histogram bins and plot axes are well aligned (that is the+    @'Nice' False@ statements may not be needed when defining the+    histogram axes);++  * I am not 100% sure I understand what is going on with the+    grid labels on the Declination axis, as I had thought I was+    asking for marks every 15 degrees, but the plot shows them+    every 30 degrees (however, if I change the @deTicks@ array then+    the marks change in ways I currently do not understand);++  * and I have decided to display Right Ascension in hours, rather than+    degrees, because why have one way to measure a value when you can+    have many!++<<images/vl/combinedplot.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1hJ5k8oAlAQUgBooBjeAGwYFdn5oBTcyAEy5ssAOmoB9AJIBhCgGUwAejABGAKyQAvgF1a4RukSoAlgHNyxAG7HuAdwuRkcdAGte+GAhQAHeLG6I0FqaehACXPAW+mFssMx8ABbQ0N7IuIqKCLYipsbQCWwARmzI3LAMhjyBIhVYigAi6GymAEKxbooJltym8IpYpDywnd29ioLQfb3G8AC08HMAbCqL8yoADLOThczcKvAiiOizCdzw-GUi0MiWdNFQGNhcURCvUL6wpS9vr5AA4gNzB5EMJCmU7j9fhIZPI+CCsGDYBDIe9mAAPOGg8GhFGQeoAUSksjkmIR2Pub0g3HE3nRpMRkApYE09xZEBC+kglgqiCYQXwBHuoEhXJ5fPIgpRYGFUqgpzMSXIG3WOKlkFsxn4+XIABZ1iqmZTOABPcECw0-GWy34DWAuBwVZiYPimBDGuhQaDG7zuKCFPxaVXWqABCr8YyIIHSi1qjH4K3BykmbjMfh8ajIxOUwoRhzcNFVfmEFVgABMOt0UCc3G85FL9EgiGMDF9qBYpQ5WZ+jkwRYE3GQLcQ4cjma7nu9vsgAEc2EhoHkuMZumOuyQ0cYyPgQcxmDGUZ3x5B3fH92rByxfcR+OgBrmBSWAMz69baQ-jqDwUyunpcKcVNhAlXLMYEnPhZ3nRcFxXIM13gDct2lGA8l2cgd2YNlx0wxNsNld9ZQTa1PCQNBMBwAViBMZghgcUpdgYBdDD4bxm3tTQdFg2VIFte0PH9JFOLVUN0BHKNCODSBHWdU8PzCSwWDYKcf3dQSJJ5cNGMQb5ZIeGxUz4aRmBKGjVMTRwU24BjjCYjwWIYe1TIkr0fThW8IxYRkdNwnDHJFONox0yBk30jwM183Ecy0+MqQLAIiwIEty0rRweFrfB6ygJsW3INtmA7cKRWQXs+AuQcAlE4CzOcqcIMCKDl14Aru3gzc0I4PcP3wsyTwC2THCYVDopvO8ouLehn31N8mspL8f16Hg+AAoDpt+arwLnOrJmgxqz1xFrEOIBdoEGsB0O84NzqlS6fmuiBtAtLrXnEykEjFZ5zUTZ7cXlUxFXwPUDTXHiHHQXwGDyHr1hENQGzWjxwfKVDHrVDUtQSXV9Sa8z6M0hw7N4pC4arCNTFQhtgv4RCCEgQzjPBN9kdxYSKpko8pKRVmPy5BSlP8FTdpFdS8ms0avrMimDKM6sBIF3E6Ms3HbNYyqQKJxs3MQDzZbeW6DxWyB-LFriJdCmgVrCC8TuvW94HvMaywrBsstbdtuEZoiitgPtSqHCrzYnFyPFqo6lxg7Xfn2hwjpOyAKAVaAwCoMqUBFsAAAoEiaT4AEotHD93cR6o21RNqACSJWF-f6y8HGG23RoIWYAE4Sxb5LnZy12C7VNXg-qsPAsjzm+vkoyBwlcPIWbwGdNeWYAHYYcnn5ZkWGfZ7AWYdSXjeIFmZ9-beWZ1EP1519nk-l7eA+r9ebfT4gNeH7ARfn5b2-dFv5DjqnepLOYdyml04XB-AOXOy9daQkga8aB3depmR+n9MAAMsao21PgZUWMTRmkIOHYuuJgbRXZi6N0HpQKBz9AGOBIpmYk20n1Q2t8LYDSvAIG2dsErjRfFNJhn5vz+Hmv+Joy1eHkJqhtEO20VZwQQlHFCvozq32oYXehgVS54kJDCEkz9ICRTzLFICApp70Dbg2asaVVAw0ys2F2eU3Y6N7hI-uO1d6flkdudqSiIH5xWvgkUcASKPHIoQSixhqI4OIPLKyNl3jK3Yp-QKhDKEy0CrQ0cw8ubEIySPHmJDuD81cZJQwGkRaqNnkFPSaYPC02ltIo8UTFaxPsnUtcasjhYHcvEXh0CrqnwNmUrmltWF1w4U+bhyi1SzQEX+RawiggOLAkHJxW0GotIkkPQm8i2q7h6XrL+RdRHqPLlotZRE9HRXzIWCUxiwCmKrKlJUVjGw2M7nYiZuJHGQRWQPXe65WoeN3F4ry+dZb3RwvuBJXFkBgzoelc+IpCjCMpnwVAUt0YPSZJCyk0L4Dg3SWWeFfokWISCmizyMCgziW4n4AmxBQa4ohuQKGTy1YIwYEjTi6pNToLAGoUshLsYK1KdFfGUdFnE0jGTXSKZkUChplLGiDNOVpLEhaIpToObwNxKPRSeSClcSFo0-BFSZWSzpikiSDThVNIcrtMRrkOmay6daa6jN+nZKTJU5idJHLVytvajwTpzBOxefgXK+V9wBqgH3b5LiuIbMOls2yfgWCcDROnDpu5jDzHKKUdSudXWqWPAM346iARfjqVGmcyzQ5xsme4zZP8+B-DAICJs0A2AXDzldJkuFMKQsgAAEkHKcAYiRkipHSIoUYBxcj5CKCIayigR3cAGNO38swAE8GnTqEQAArIqWkcTf39TwAszbbbwDABMK9qBYC3jAH4AAGsuXAKgAAc6xd3rCbo+ee76yFIAYJnTV3FNT8CRiATQQA Open this visualization in the Vega Editor (although the link is long, and may not work with Internet Explorer)>++@+let trans = transform+              . calculateAs \"datum.RA_ICRS / 15\" \"RA\"++    quant n = [ PName n, PmType Quantitative ]++    big = 400+    small = 100+    wmain = width big+    hmain = height big+    wsub = width small+    hsub = height small+    noTitle = PAxis [ AxNoTitle ]++    raAxis = [ PScale [ SDomain (DNumbers [ 0, 24 ])+                      , SNice (IsNice False)+                      ]+             , PSort [ Descending ]+             , PAxis [ AxTitle \"Right Ascension (hours)\" ]+             ]++    deMin = -90+    deMax = 90+    deStep = 15++    -- we do not get ticks/grids at all these values, but it does+    -- something (e.g. if do not specify the axis ticks are different)+    --+    deTicks = Numbers [ deMin, deMin + deStep .. deMax ]+    deAxis = [ PScale [ SDomain (DNumbers [ deMin, deMax ])+                      , SNice (IsNice False)+                      ]+             , PAxis [ AxTitle \"Declination (degrees)\"+                     , AxValues deTicks+                     ]+             ]++    colorEnc = color [ MSelectionCondition (SelectionName \"pick\")+                         [ MName \"Cluster\", MmType Nominal ]+                         [ MString \"grey\" ]+                     ]+    mapEnc = encoding+               . position X (quant \"RA\" ++ raAxis)+               . position Y (quant \"DE_ICRS\" ++ deAxis)+               . colorEnc++    circleMark = mark Circle [ MOpacity 0.5 ]++    mapSpec = asSpec [ mapEnc []+                     , circleMark+                     , wmain+                     , hmain+                     , selCluster []+                     ]++    -- histogram of the RA values+    --+    raBinning = [ PBin [ 'Extent' 0 24+                       , Step 2+                       , Nice False+                       ]+                , PSort [ Descending ]+                , PAxis []+                ]++    -- histogram of the Declination values+    --+    deBinning = [ PBin [ Extent deMin deMax+                       , Step deStep+                       , Nice False+                       ]+                , PAxis []+                ]++    histAxis = [ PAggregate Count+               , PmType Quantitative+               , noTitle+               , PScale [ SDomain (DNumbers [ 0, 3000 ]) ]+               ]++    raEnc = encoding+              . position X (quant \"RA\" ++ raBinning)+              . position Y histAxis++    deEnc = encoding+              . position Y (quant \"DE_ICRS\" ++ deBinning)+              . position X histAxis++    allRA = [ raEnc []+            , mark Bar [ MColor \"gray\" ]+            ]+    filtRA = [ filterCluster []+             , raEnc+                 . colorEnc+                 $ []+             , mark Bar []+             ]++    allDE = [ deEnc []+            , mark Bar [ MColor \"gray\" ]+            ]+    filtDE = [ filterCluster []+             , deEnc+                 . colorEnc+                 $ []+             , mark Bar []+             ]++    raSpec = asSpec [ wmain, hsub, layer [ asSpec allRA, asSpec filtRA ] ]+    deSpec = asSpec [ hmain, wsub, layer [ asSpec allDE, asSpec filtDE ] ]++    borderSpacing = 20++    mapAndDecSpec = asSpec [ spacing borderSpacing+                           , 'bounds' 'Flush'+                           , hConcat [ mapSpec, deSpec ]+                           ]++    histSpecs = [ raSpec, mapAndDecSpec ]++    -- select the cluster which the star belongs to; do not use+    -- \"nearest click\" as that means a user can not cancel the+    -- selection.+    --+    pick = \"pick\"+    selCluster = selection+                   . select pick Single [ Fields [ \"Cluster\" ] ]++    filterCluster = transform+                      . filter (FSelection pick)++    plxOpts = [ PScale [ SType ScLog, SNice (IsNice False) ]+              , PAxis [ AxTitle \"parallax (milli-arcsecond)\" ]+              ]+    gmagOpts = [ PAxis [ AxTitle \"G magnitude\" ] ]++    encData = encoding+                . position X (quant \"plx\" ++ plxOpts)+                . position Y (quant \"Gmag\" ++ gmagOpts)++    parallaxSpec = asSpec [ width (big + borderSpacing + small)+                          , encData+                              . colorEnc+                              $ []+                          , circleMark+                          , selCluster []+                          ]++    allSpecs = [ asSpec [ spacing borderSpacing+                        , bounds Flush+                        , vConcat histSpecs+                        ]+               , parallaxSpec ]+++in toVegaLite+   [ gaiaData+   , trans []+   , vConcat allSpecs+     -- remove the "other" axis (e.g. top of Y, right for X)+   , configure+       . configuration (View [ ViewStroke (Just \"transparent\") ])+       $ []+   , title \"Gaia data from arXiv:1804.09378\" [ 'TAnchor' 'AMiddle' ]+   ]+@++Here is the visualization after selecting a star:++<<images/vl/combinedplot-selected.png>>++-}++combinedPlot :: VegaLite+combinedPlot =+  let trans = transform+                . calculateAs "datum.RA_ICRS / 15" "RA"++      quant n = [ PName n, PmType Quantitative ]++      big = 400+      small = 100+      wmain = width big+      hmain = height big+      wsub = width small+      hsub = height small+      noTitle = PAxis [ AxNoTitle ]++      raAxis = [ PScale [ SDomain (DNumbers [ 0, 24 ])+                        , SNice (IsNice False)+                        ]+               , PSort [ Descending ]+               , PAxis [ AxTitle "Right Ascension (hours)" ]+               ]++      deMin = -90+      deMax = 90+      deStep = 15++      -- we do not get ticks/grids at all these values, but it does+      -- something (e.g. if do not specify the axis ticks are different)+      --+      deTicks = Numbers [ deMin, deMin + deStep .. deMax ]+      deAxis = [ PScale [ SDomain (DNumbers [ deMin, deMax ])+                        , SNice (IsNice False)+                        ]+               , PAxis [ AxTitle "Declination (degrees)"+                       , AxValues deTicks+                       ]+               ]++      colorEnc = color [ MSelectionCondition (SelectionName "pick")+                           [ MName "Cluster", MmType Nominal ]+                           [ MString "grey" ]+                       ]+      mapEnc = encoding+                 . position X (quant "RA" ++ raAxis)+                 . position Y (quant "DE_ICRS" ++ deAxis)+                 . colorEnc++      circleMark = mark Circle [ MOpacity 0.5 ]++      mapSpec = asSpec [ mapEnc []+                       , circleMark+                       , wmain+                       , hmain+                       , selCluster []+                       ]++      -- histogram of the RA values+      --+      raBinning = [ PBin [ Extent 0 24+                         , Step 2+                         , Nice False+                         ]+                  , PSort [ Descending ]+                  , PAxis []+                  ]++      -- histogram of the Declination values+      --+      deBinning = [ PBin [ Extent deMin deMax+                         , Step deStep+                         , Nice False+                         ]+                  , PAxis []+                  ]++      histAxis = [ PAggregate Count+                 , PmType Quantitative+                 , noTitle+                 , PScale [ SDomain (DNumbers [ 0, 3000 ]) ]+                 ]++      raEnc = encoding+                . position X (quant "RA" ++ raBinning)+                . position Y histAxis++      deEnc = encoding+                . position Y (quant "DE_ICRS" ++ deBinning)+                . position X histAxis++      allRA = [ raEnc []+              , mark Bar [ MColor "gray" ]+              ]+      filtRA = [ filterCluster []+               , raEnc+                   . colorEnc+                   $ []+               , mark Bar []+               ]++      allDE = [ deEnc []+              , mark Bar [ MColor "gray" ]+              ]+      filtDE = [ filterCluster []+               , deEnc+                   . colorEnc+                   $ []+               , mark Bar []+               ]++      raSpec = asSpec [ wmain, hsub, layer [ asSpec allRA, asSpec filtRA ] ]+      deSpec = asSpec [ hmain, wsub, layer [ asSpec allDE, asSpec filtDE ] ]++      borderSpacing = 20++      mapAndDecSpec = asSpec [ spacing borderSpacing+                             , bounds Flush+                             , hConcat [ mapSpec, deSpec ]+                             ]++      histSpecs = [ raSpec, mapAndDecSpec ]++      -- select the cluster which the star belongs to; do not use+      -- "nearest click" as that means a user can not cancel the+      -- selection.+      --+      pick = "pick"+      selCluster = selection+                     . select pick Single [ Fields [ "Cluster" ] ]++      filterCluster = transform+                        . filter (FSelection pick)++      plxOpts = [ PScale [ SType ScLog, SNice (IsNice False) ]+                , PAxis [ AxTitle "parallax (milli-arcsecond)" ]+                ]+      gmagOpts = [ PAxis [ AxTitle "G magnitude" ] ]++      encData = encoding+                  . position X (quant "plx" ++ plxOpts)+                  . position Y (quant "Gmag" ++ gmagOpts)++      parallaxSpec = asSpec [ width (big + borderSpacing + small)+                            , encData+                                . colorEnc+                                $ []+                            , circleMark+                            , selCluster []+                            ]++      allSpecs = [ asSpec [ spacing borderSpacing+                          , bounds Flush+                          , vConcat histSpecs+                          ]+                 , parallaxSpec ]+++  in toVegaLite+     [ gaiaData+     , trans []+     , vConcat allSpecs+     -- remove the "other" axis (e.g. top of Y, right for X)+     , configure+         . configuration (View [ ViewStroke (Just "transparent") ])+         $ []+     , title "Gaia data from arXiv:1804.09378" [ TAnchor AMiddle ]+     ]+++-- $otherstuff+-- The tutorial ends not with a bang, but a few random visualizations+-- I thought of and couldn't find a better place to put them!++{-|++This visualization started out when I asked myself if I could+repeat the X axis at the top of the plot. I started off by+trying to use 'configuration' with the 'AxisTop' constructor,+but this didn't work (perhaps I didn't turn on the necessary+option), so I ended up with the following. It does show off+the use of 'AxLabelExpr' and 'AxDataCondition', but is not+perhaps the most-digestible visualization one could create!++As I could not work out how to duplicate the X axis with only+a single layer, I got creative and duplicated the data and+in the second layer moved the X axis to the top of the plot+with 'AxOrient', and ensured the data would not be displayed+(by setting the 'Text' value to the empty string).++The axis labels and the tick marks for the two X axes make+use of the @datum.index@ field, which is in the range 0 to 1 inclusive,+which I multiply by 8 (one less than the total number of clusters) and+check if the result is odd or even (ignoring the possibility+of floating-point inaccuracies in the conversion). The odd values are displayed+on the bottom axis and the even values on the top (the first+cluster, in this case @Blanco1@, has an index value of 0,+so is displayed on the top axis). The 'AxLabelExpr' option+is used to determine the label contents (if the condition+holds then it uses a trimmed and truncated version of the+default label, otherwise it is blank), and+'AxDataCondition' is used to control the opacity of the+tick marks. I had hoped to show some of the label-overlap+strategies in play here - controlled by 'AxLabelOverlap' - but+they didn't work well with the data and visualization size,+and I realised I could play with the new-to-Vega-Lite-4+'AxLabelExpr' and 'AxDataCondition' capabilities.++Normally a grid is not drawn for 'Nominal' axes, but I turn+it on (for the first layer) with 'AxGrid' just to help guide+the eye.++<<images/vl/duplicateaxis.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAuBOCGA7AzgMwPawLaQFxgG1wIxhIBzWdAVwAcAjATz0MgGEAba5aAU1kgBdADRR45Sr3Lw+LAmXS0WkAMY1E0SKMjxkyxNSz1+kAL6DTxEcUgATGfBagSUarA7KAFtGi1kuAHoAhAB3ADpyAEtoT2p6bn41DV4NMLUsAIARGnIAITcAa14AzwA3KXgArF0+WBLy6QD7aErpSPgAWnhOgDYARh6uvoAGDpb6Dl4++DDEdA7PXnhbfjDoZFKtYghIDGwZJ22SSFp4WGReQ5cXSABxavJ9Q2MBYSObgCUAQQB9AEk2B8AMpPIwmN7XY60DgAD1BLy2kJ2mQAov9ASD8JADGDXu9jrwftC4VicQj8ZYXJSwKYIVAACTIFSLapeHx+QIBBozKIxOJhSLoAJMlmVbkdDjRYqlAAsYQAVsh0IhEVAOPBGCZ8EQXM5rpBqrACsoVJFYCpJqqbik1LZIohHvg9ZDICTSPibqhIrwOLZlJxuLUrUiYIxaJdSegsPb4B46UixDDInonR79erjBwvg7LfhhvGE1BMN6NMp6OgfFHgwnIBmfSiYbQBFjIqgABRt5qGAWIFYwsAAKjAAA4AJRgACkYAATGAALxzvqiODURAqGS8NtwSJYTsybt1jij0QAVmPYAA5BfR9WQ9BIioCgB5U6m6DMVOF-WlWPUCNgfM0xdJI7XvZUnEgH8uH-JcoD4HhlD3aBu3tPtBxHccp1nBc+jMICSFpfCdkoSI-XwFdeALGt72gXMoADHgTHw6lIUImsP3dL9dm9X14XBfDQ3DZQAEdqCQGiZEicpbxueAkxTUgYGiOjIAAOWefgwHQVAwB4M49BY65DIgQy2JIZ1jkNY0nRgXgYU0LEtDgsN-1s+yzCoqAbXQO0HSuEM3Qsl0vR9Mj6K4Ri8S498hMjaNEFjGTjjk5N-K4w9s3IOjAK-HZixSBy4MUJKbkPBsm2UVsOy7LAezQocx0nGd5znfMwBXNcNy3WAdyQg94Ezc8z1EK8b08l170fF94DfDigsLSDf3-HLcp2EDokFFUbKgv8WFg2yEKxPratQuz0MarCWuGPDVrMriSLC1BYwucb9RouiDA4DhmLTO79TmgSQt40kNKihaYtc0TxOiSTpNenYUoUsh3v-T6OGMgiKSOalrDW5UvUdUhLFMIA Open this visualization in the Vega Editor>++@+let trans = transform+            . aggregate [ opAs Count \"\" \"number\" ]+                        [ \"Cluster\" ]++    xAxis f = position X [ PName \"Cluster\"+                         , PmType Nominal+                         , PAxis [ 'AxLabelAngle' 0+                                 , 'AxOrient' (if f then SBottom else STop)+                                 , if f+                                   then AxTitle \"Cluster\"+                                   else AxNoTitle+                                 , 'AxLabelExpr' (xlabels f)+                                 , 'AxDataCondition'+                                   (Expr (xticks f))+                                   ('CAxTickOpacity' 1 0)+                                 , 'AxGrid' f+                                 ]+                         ]++    xlabels f =+      let v = if f then \"1\" else \"0\"+      in \"if((datum.index * 8) % 2 ==\" <> v <> \", truncate(trim(datum.label), 5), '')\"++    xticks f =+      let v = if f then \"1\" else \"0\"+      in \"(datum.index * 8) % 2 ==\" <> v++    yAxis f = position Y [ PName \"number\"+                         , PmType Quantitative+                         , PAxis [ if f+                                   then AxTitle \"Number of stars\"+                                   else AxNoTitle ]+                         ]++    -- f is True indicates first Layer (bottom X axis, should display+    -- the Y axis).+    enc f = encoding+            . xAxis f+            . yAxis f++    dataLayer = asSpec [ enc True []+                       , mark Circle []+                       ]++    axLayer = asSpec [ enc False []+                     , mark Text [ MText \"\" ]+                     ]++in toVegaLite [ gaiaData+              , trans []+              , layer [ dataLayer, axLayer ]+              ]+@++If anyone can come up with a simpler way to duplicate the X axis I'm all+ears!++-}++duplicateAxis :: VegaLite+duplicateAxis =+  let trans = transform+              . aggregate [ opAs Count "" "number" ]+                          [ "Cluster" ]++      -- Encode the X axis, where True indicates the lower axis+      -- and False the upper axis.+      --+      xAxis f = position X [ PName "Cluster"+                           , PmType Nominal+                           , PAxis [ AxLabelAngle 0+                                   , AxOrient (if f then SBottom else STop)+                                   , if f+                                     then AxTitle "Cluster"+                                     else AxNoTitle+                                   , AxLabelExpr (xlabels f)+                                   , AxDataCondition+                                     (Expr (xticks f))+                                     (CAxTickOpacity 1 0)+                                   , AxGrid f+                                   ]+                           ]++      -- For the bottom want every "odd" value, top every "even" value,+      -- so that the are alternated, but how do we encode this with the+      -- Vega expression syntax? There is a datum.index which is 0 to 1+      --+      -- How about just subsetting the strings for now+      xlabels f =+        let v = if f then "1" else "0"+        in "if((datum.index * 8) % 2 ==" <> v <> ", truncate(trim(datum.label), 5), '')"++      -- had hoped could use datum.label but there's no obvious guarantee+      -- of ordering of operations (or when the AxLabelExpr expression is+      -- evaluated), so repeat the logic.+      --+      xticks f =+        let v = if f then "1" else "0"+        in "(datum.index * 8) % 2 ==" <> v++      yAxis f = position Y [ PName "number"+                           , PmType Quantitative+                           , PAxis [ if f+                                     then AxTitle "Number of stars"+                                     else AxNoTitle ]+                           ]++      enc f = encoding+              . xAxis f+              . yAxis f++      dataLayer = asSpec [ enc True []+                         , mark Circle []+                         ]++      axLayer = asSpec [ enc False []+                       -- create an "invisible" mark+                       , mark Text [ MText "" ]+                       ]++  in toVegaLite [ gaiaData+                , trans []+                , layer [ dataLayer, axLayer ]+                ]+++{-|++Way back in the tutorial I noted - in 'densityParallaxGrouped' - that+setting the 'density' option 'DnCounts' to @True@ resulted in+counts that were too high. This is because the values need to be+divided by the bin width, as shown in this visualization, where I:++- use an explicit grid for the density calculation, choosing the+  'DnExtent' and 'DnSteps' parameters to create a bin width of+  0.1 in parallax;++- sum up the resulting KDE (the @\"ykde\"@ field) to create @\"ycounts\"@;++- normalize the counts by the bin with using 'calculateAs' to+  create the @\"count\"@ field;++- which is plotted as a diamond, on top of a line showing the+  actual counts (calculated following 'starCount').++<<images/vl/comparecounts.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zUAAkFELRJg0k5CotCsYXYnB4TDYImo31+RhBTjwHG0ugALEwAFYUcTrKB4WAATzaqAA2h1Cqd4PQxBRsrlCGSNmhICwcMoyNwCQzIEM8HxzJAALopKCwFisgwIfgM4CQERkBqiLASVKiiiK5Qqh6Cl5VYX3SAmHAaBpIsTS96nKSiaBsMT1VAUzpXZmZNj8PDQBq8-nTKDwAlkaXXESyO2wAhve6YLmO6MZN0er0HJUqy0bSABoMNACOWFgEg4CDY+lxTMgsAWbHVjszHGC3s1iUgutmrYw7ajRSdmCpBdpOVkDPjPc6rPZnO5PrMbX1TMwpm5Cw0cVVkAJK+lc-nkFTzdQVKw-HTszOC0kKtJAGYRVffNvyzPKIQAEwAdl8J86cRpHFjUEuO4mS7DZR1OccsA5f8SR5PkZzWB8MzFCVDEkGU5QVA4KGaNdFwOAk93VEUsndT0Gg3VdtXjEDZllPCoD3NchAjIQsHxNCDlsZomAIpsKDAagwD8Ft7kQzAjRNONHzYAAvYMwBfXxP3jSAzDZLQGiCWAhBNL9MAoIhYGzTjHFkcQvT0-1A3kyAyBEO18nuGiMmtERbXtCpyxdWVEzIg5pwFYisxsiIwzECMW0s9dPJ3XzkwYpsywzYLc3zQtEHgEsLXjBcqxrZlMvgBt-L4kTgKc550m3XdxDdB00CeB4gA Open this visualization in the Vega Editor>++@+let densTrans = transform+            . density \"plx\" [ DnAs \"xkde\" \"ykde\"+                            , DnGroupBy [ \"Cluster\" ]+                            , DnCounts True+                            , DnExtent 3 30+                            , 'DnSteps' 270+                            ]+            . aggregate [ opAs Sum \"ykde\" \"ycounts\" ]+                        [ \"Cluster\" ]+            . calculateAs \"datum.ycounts / 10\" \"count\"++    enc = encoding+          . position X [ PName \"Cluster\"+                       , PmType Nominal+                       ]+          . position Y [ PName \"count\"+                       , PmType Quantitative+                       , PAxis [ AxTitle \"Counts\" ]+                       ]++    densLayer = asSpec [ densTrans []+                       , enc []+                       , mark Point [ MShape 'SymDiamond'+                                    , MStroke \"black\"+                                    , MSize 200+                                    ]+                       ]++    countTrans = transform+                 . aggregate [ opAs Count \"\" \"count\" ] [ \"Cluster\" ]++    countLayer = asSpec [ countTrans [], enc [], mark Line [] ]++in toVegaLite+     [ gaiaData+     , layer [ countLayer, densLayer ]+     ]+@++Note that the same encoding specification is used on both layers,+since I arranged the data transforms to create two columns -+@\"Cluster\"@ and @\"count\"@ - in both cases.++-}++compareCounts :: VegaLite+compareCounts =+  let densTrans = transform+              . density "plx" [ DnAs "xkde" "ykde"+                              , DnGroupBy [ "Cluster" ]+                              , DnCounts True+                              , DnExtent 3 30+                              , DnSteps 270+                              ]+              . aggregate [ opAs Sum "ykde" "ycounts" ]+                          [ "Cluster" ]+              . calculateAs "datum.ycounts / 10" "count"++      enc = encoding+            . position X [ PName "Cluster"+                         , PmType Nominal+                         ]+            . position Y [ PName "count"+                         , PmType Quantitative+                         , PAxis [ AxTitle "Counts" ]+                         ]++      densLayer = asSpec [ densTrans []+                         , enc []+                         , mark Point [ MShape SymDiamond+                                      , MStroke "black"+                                      , MSize 200+                                      ]+                         ]++      countTrans = transform+                   . aggregate [ opAs Count "" "count" ] [ "Cluster" ]++      countLayer = asSpec [ countTrans [], enc [], mark Line [] ]++  in toVegaLite+       [ gaiaData+       , layer [ countLayer, densLayer ]+       ]+++{-|++In this example I compare the parallax values++- as the raw distribution, using the ticks display we saw in+  the very first plot, 'stripPlot', (although with a few+  adjustments)++- against a smoothed version of the distribution, calculated using+  the 'regression' transform (e.g. 'densityParallax').++The only new things here are configuration options+for the X axis - that is, the use of 'AxLabels', along with+'AxNoTitle', to ensure the X axis of the density plot only has+grid lines - and the legend options were set to+center the title.++<<images/vl/parallaxview.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAmCGAutIC4yghSBXATgGxSgAt54AHAZ2QHpqdYB3AOgHMBLeIrAIywoFMcAYwD2AO3j8JTUQFtqAERFYWAIVwBrftSIA3fi1jVZsCpJw79h6nETVDbWAFpYzgGwBGNy48AGJ4jcePwesExiIk5E-LDQgkzwFLqQADTgGJAAZiI4JvCE6BiYZLA4AgXpRZgA4iYshJBiWLLcgqmVVZAASgCCAPoAkgDCXQDKDU0tbWlVGWR4AB4Tza047bOYCgCigyPjqI0r0x1FkPx980sHk6uQJ2AAvh1PEA8zULqiYkIIhADaHUKp3g9DEFGyuX+9wgwEgLBwyjI3AAnv9IEM8HxzJAALopKCmNG6WCY-ipKBxMEcVF4ilSCjUhqXSAvKp4+6QEw4DQNPBsMRk96nBhsaCcQhuXy+IUZATBITwNjiCobKDBFhSaAFSDcflag7qzXkyDwZFkMkHBliFjBY2ZNj8PDQChojFYto41lFN4cqSiaD8+qoIGdUR4HIq1VQe2O-VQN1mY5RqAUH624OQVPRWQWqA-SQsHLIvwsmWzE1m3ONESyfkk9ZRyCGsRxkOqyA5B0SBrcESkGsN5MmjjpqCjR38BVgWBgISYxNrMsbYfwYI9b5ECMHWvQaC26EYL1VH3tkQlISM4MHzDE0mEXxMADMS9OXwDiuVGdvWFzHnxmYnBUlTEXkDCNI9vRfKArjQa9owdJ0Gm-QU4MzNNc1haAa1gfl-mfMBH18WkK3NXkRHqf8xDYIRc0yEkBBPRtTVIg4AEcsFgCQOAQNh9EHZdYAWNgXQzPBYFaPARLAOjJP4f9FVXXMmjwPAIMPKDIFRK8hxjRCDkpBlTX48tmKrdjOIUni+KgzBBOE7UFNHSAFHpRk1Nee4j0YmEOS5HkDkVIQeSXSARTFIgJSlEK-REANrUjcswy3NAsgQuN0XnbF5MrCYazrAh-2bONlNUjSz1gC8jO0xtkPvJhfAAVhsvNxHfYDtVq1AH3wgD5Q-ECDTAlsWQPbzOhgttOl09LmWatCSQwmBsNw1A-nwwjiNMsiKKgKiaMIGSGLmra2I4rjEEVazULsqTYUcqsAAVShJMSFjAAAKEwKAAShG1U1K89J2UwAASLN+BMBoSHIKhaCsMJ2E4HgmCVahwZMah4acPlJExgAWJgACsKGVd5M3PQN7zJ3ssBbKSsnnCKya+e0gzQJ4HiAA Open this visualization in the Vega Editor>++@+let plxScale = PScale [ SType ScLog+                      , SNice (IsNice False)+                      , SDomain (DNumbers [3, 30])+                      ]++    opacityEnc ounsel osel =+      opacity [ MSelectionCondition (SelectionName selName)+                [ MNumber osel ]+                [ MNumber ounsel ]+              ]++    tickEnc = encoding+              . position X [ PName \"plx\"+                           , PmType Quantitative+                           , plxScale+                           , PAxis [ AxTitle \"Parallax (mas)\" ]+                           ]+              . color [ MName \"Cluster\"+                      , MmType Nominal+                      , MLegend []+                      ]+              . opacityEnc 0.05 0.3++    plotWidth = width 600++    tickLayer = asSpec [ plotWidth+                       , tickEnc []+                       , mark Tick [ ] ]++    densTrans = transform+                . density \"plx\" [ DnGroupBy [ \"Cluster\" ]+                                  , DnAs "value" "density"+                                  ]+    densEnc = encoding+              . position X [ PName \"value\"+                           , PmType Quantitative+                           , plxScale+                           , PAxis [ AxNoTitle+                                   , 'AxLabels' False+                                   ]+                           ]+              . position Y [ PName \"density\"+                           , PmType Quantitative+                           , PAxis [ AxTitle \"Density\" ]+                           ]+              . color [ MName \"Cluster\"+                      , MmType Nominal+                      , MLegend [ LOrient LOBottom+                                , 'LTitleAnchor' AMiddle+                                , LTitle \"Select a cluster\"+                                ]+                      , MScale [ SScheme "category10" [] ]+                      ]+              . opacityEnc 0.3 1++    densLayer = asSpec [ plotWidth+                       , densTrans []+                       , densEnc []+                       , sel []+                       , mark Line [ ]+                       ]++    selName = \"legend\"+    sel = selection+          . select selName Single [ BindLegend (BLField \"Cluster\") ]++in toVegaLite+    [ gaiaData+    , spacing 0+    , bounds Flush+    , vConcat [ densLayer, tickLayer ]+    ]+@++I have also changed the color scheme to @\"category10\"@, which isn't+necessarily any better than the default (@\"tableau10\"@), but is at least+different (I was hoping to get a better separation in color space for+the IC2391 and IC2602 clusters, but quickly gave up after+<https://vega.github.io/vega/docs/schemes/index.html#categorical trying out a few options>).++Here is the visualization after selecting the label \"@NGC2451@\"+in the legend:++<<images/vl/parallaxview-selected.png>>++-}++parallaxView :: VegaLite+parallaxView =+  let plxScale = PScale [ SType ScLog+                        , SNice (IsNice False)+                        , SDomain (DNumbers [3, 30])+                        ]++      opacityEnc ounsel osel =+        opacity [ MSelectionCondition (SelectionName selName)+                  [ MNumber osel ]+                  [ MNumber ounsel ]+                ]++      tickEnc = encoding+                . position X [ PName "plx"+                             , PmType Quantitative+                             , plxScale+                             , PAxis [ AxTitle "Parallax (mas)" ]+                             ]+                . color [ MName "Cluster"+                        , MmType Nominal+                        , MLegend []+                        ]+                . opacityEnc 0.05 0.3++      plotWidth = width 600++      tickLayer = asSpec [ plotWidth+                         , tickEnc []+                         , mark Tick [ ] ]++      densTrans = transform+                  . density "plx" [ DnGroupBy [ "Cluster" ]+                                  , DnAs "value" "density"+                                  ]+      densEnc = encoding+                . position X [ PName "value"+                             , PmType Quantitative+                             , plxScale+                             , PAxis [ AxNoTitle+                                     , AxLabels False+                                     ]+                             ]+                . position Y [ PName "density"+                             , PmType Quantitative+                             , PAxis [ AxTitle "Density" ]+                             ]+                . color [ MName "Cluster"+                        , MmType Nominal+                        , MLegend [ LOrient LOBottom+                                  , LTitleAnchor AMiddle+                                  , LTitle "Select a cluster"+                                  ]+                          -- fortunately setting the color scheme+                          -- here applies it to the tick encoding too+                        , MScale [ SScheme "category10" [] ]+                        ]+                . opacityEnc 0.3 1++      densLayer = asSpec [ plotWidth+                         , densTrans []+                         , densEnc []+                         , sel []+                         , mark Line [ ]+                         ]++      selName = "legend"+      sel = selection+            . select selName Single [ BindLegend (BLField "Cluster") ]++      -- TODO: select the lines as well (and ticks?), not sure+      -- how as VL docs suggest both On and Clear need to be set+      -- but I couldn't quickly get it to work++  in toVegaLite+      [ gaiaData+      , spacing 0+      , bounds Flush+      , vConcat [ densLayer, tickLayer ]+      ]++{-+See https://github.com/DougBurke/hvega/issues/88+-}++aitoffTrans :: FieldName -> FieldName -> BuildTransformSpecs+aitoffTrans lng lat =+  calculateAs (lng <> ">180?(" <> lng <> "-360)*PI/-180 : " <> lng <> "*PI/-180") "lambda"+  . calculateAs (lat <> "*PI/180") "phi"+  . calculateAs "acos(cos(datum.phi)*cos(datum.lambda/2))" "alpha"+  . calculateAs "datum.alpha == 0 ? 1 : sin(datum.alpha) / datum.alpha" "sincAlpha"+  . calculateAs "360*cos(datum.phi)*sin(datum.lambda/2)/(PI*datum.sincAlpha)" "x"+  . calculateAs "180*sin(datum.phi)/(PI*datum.sincAlpha)" "y"+++graticuleData :: Double -> Double -> [DataColumn] -> Data+graticuleData lngStep latStep =+  let lngVals = [-180, lngStep - 180 .. 180]+      latVals = [-90, latStep - 90 .. 90]++      nlng = length lngVals+      nlat = length latVals++      lng = concat (replicate nlat lngVals)+      lat = concatMap (replicate nlng) latVals++  in dataFromColumns []+     . dataColumn "lng" (Numbers lng)+     . dataColumn "lat" (Numbers lat)+++graticuleSpec :: [VLSpec]+graticuleSpec =+  let trans = transform+              . aitoffTrans "datum.lng" "datum.lat"++      enc = encoding+            . position X [ PName "x", PmType Quantitative, PAxis [] ]+            . position Y [ PName "y", PmType Quantitative, PAxis [] ]++      encParallel = enc+                    . detail [ DName "lat", DmType Nominal ]+      encMeridian = enc+                    . detail [ DName "lng", DmType Nominal ]+                    . order [ OName "lat", OmType Quantitative ]++      spec lngStep latStep encs =+        asSpec [ graticuleData lngStep latStep []+               , trans []+               , encs []+               , mark Line [ MStrokeWidth 0.1, MStroke "black" ]+               ]++      specParallel = spec 30 10 encParallel+      specMeridian = spec 10 2 encMeridian++  in [ specParallel, specMeridian ]+++aitoffConfig :: [ConfigureSpec] -> PropertySpec+aitoffConfig =+  configure+  . configuration (View [ ViewStroke Nothing ])+  . configuration (FacetStyle [ FSpacing 0 ])+  . configuration (HeaderStyle [ HLabelAngle 0 ])+  . configuration (Legend [ LeOrient LOBottom, LeNoTitle ])+  . configuration (Axis [ Domain False+                        , Grid False+                        , Labels False+                        , Ticks False+                        , NoTitle+                        ])++++-- $aitoff+--+-- Thanks to Jo Wood for+-- <https://github.com/gicentre/litvis/blob/master/examples/gaia.md coming up with these examples>.+-- They are similar to 'skyPlot', but instead of using one of the pre-defined+-- projections, they creates their own: the+-- <https://en.wikipedia.org/wiki/Aitoff_projection Aitoff projection>.+--+--  I follow Jo's example and break out four helper routines:+--+--  @+--  aitoffTrans :: 'FieldName' -> 'FieldName' -> 'BuildTransformSpecs'+--  aitoffTrans ra dec =+--    calculateAs (ra <> \">180?(\" <> ra <> \"-360)*PI/-180 : \" <> ra <> \"*PI/-180\") \"lambda\"+--    . calculateAs (dec <> \"*PI/180\") \"phi\"+--    . calculateAs \"acos(cos(datum.phi)*cos(datum.lambda/2))\" \"alpha\"+--    . calculateAs \"datum.alpha == 0 ? 1 : sin(datum.alpha) / datum.alpha\" \"sincAlpha\"+--    . calculateAs \"360*cos(datum.phi)*sin(datum.lambda/2)/(PI*datum.sincAlpha)\" \"x\"+--    . calculateAs \"180*sin(datum.phi)/(PI*datum.sincAlpha)\" \"y\"+--  @+--+--  This is used to convert position values to diplay coordinates.+--  The first two calculations convert the angles into radians, first ensuring right+--  ascension is scaled between -180 and 180 degrees rather than 0 to 360 degrees+--  and flipped so we are looking \'out\' from the centre the sphere not \'in\' from outside+--  (we've seen this before, but not in such a condensed form).+--  The next two calculate the intermediate alpha value and its cardinal sine.+--  The final pair use lambda, phi and alpha to calculate the projected x and y coordinates.+--+--  @+--  graticuleData :: Double -> Double -> ['DataColumn'] -> 'Data'+--  graticuleData lngStep latStep =+--    let lngVals = [-180, lngStep - 180 .. 180]+--        latVals = [-90, latStep - 90 .. 90]+--+--        nlng = length lngVals+--        nlat = length latVals+--+--        lng = concat (replicate nlat lngVals)+--        lat = concatMap (replicate nlng) latVals+--+--    in dataFromColumns []+--       . dataColumn \"lng\" (Numbers lng)+--       . dataColumn \"lat\" (Numbers lat)+--  @+--+--  This routine just sets up a bunch of points which indicite the grid lines,+--  and is used in the following function.+--+--  @+--  graticuleSpec :: ['VLSpec']+--  graticuleSpec =+--    let trans = transform+--                . aitoffTrans \"datum.lng\" \"datum.lat\"+--+--        enc = encoding+--              . position X [ PName \"x\", PmType Quantitative, PAxis [] ]+--              . position Y [ PName \"y\", PmType Quantitative, PAxis [] ]+--+--        encParallel = enc+--                      . 'detail' [ 'DName' \"lat\", 'DmType' Nominal ]+--        encMeridian = enc+--                      . detail [ DName \"lng\", DmType Nominal ]+--                      . 'order' [ 'OName' \"lat\", 'OmType' Quantitative ]+--+--        spec lngStep latStep encs =+--          asSpec [ graticuleData lngStep latStep []+--                 , trans []+--                 , encs []+--                 , mark Line [ MStrokeWidth 0.1, MStroke \"black\" ]+--                 ]+--+--        specParallel = spec 30 10 encParallel+--        specMeridian = spec 10 2 encMeridian+--+--    in [ specParallel, specMeridian ]+--  @+--+--  We then project the lines of longitude and latitude using our Aitoff transformation+--  and combine them as two layers. Note the use of the 'detail' channel to separate the+--  coordinates that make up each line of constant longitude (meridian) and+--  latitude (parallel) and the 'order' channel to sequence the coordinates+--  of each meridian line in latitude order.+--+--  @+--  aitoffConfig :: ['ConfigureSpec'] -> 'PropertySpec'+--  aitoffConfig =+--    configure+--    . configuration (View [ ViewStroke Nothing ])+--    . configuration ('FacetStyle' [ 'FSpacing' 0 ])+--    . configuration ('HeaderStyle' [ 'HLabelAngle' 0 ])+--    . configuration ('Legend' [ 'LeOrient' LOBottom, 'LeNoTitle' ])+--    . configuration ('Axis' [ 'Domain' False+--                          , 'Grid' False+--                          , 'Labels' False+--                          , 'Ticks' False+--                          , 'NoTitle'+--                          ])+--  @+--+--  The configuration hides the border line and tweaks a number of settings,+--  some of which we have seen applied directly to the marks themselves.++{-|++With the helper routines, the actual plot is not very different to other+plots (but note that unlike 'skyPlot' we __do not__ use 'projection' since+we are doing it all ourselves).++<<images/vl/skyplotaitoff.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMAmAHAVgBpwoBjAewDsAzJDMUCCGWAQwBNYAnO4SAGxYAjWHwCCFRH1h0ADAF8ijKADd4sAO49IAZxScyAa2mYKAVz58FxJlRYlYaTL20AHO-AmyrSyCwAe8No81oyQbGQAtiwedLZ82rCKSlACwvGxLPGJIUyInPBsGVlJPijwKFJ0ZhYloWUkBkGYcQkh3qFSiLAUhU6QZPndjlCCZCgokZAEUGUVxmDVlsTtYSwoLME+ppx8dDDjLtroAPTHnCzqAHSI5dCmgqYJnOQUKEOX5BHHACJkpogAIW2RmO0GUsEQLGOUV0XFB4MhxzYayhkPgLAAtCxMQA2ACMOKxeJkGPWgikeJYlwoZAxcHYXEuKG0yimIUgVAGUWGDGSkDcnASm2STAA4lFEHszBFhNxaj4AEqiAD6AEkAMIKgDKUtMMq4bJFTBcfD8uv1cpyoW+AFE1ZqdZhINLZYajZBYMqTWanS6DVa5G1lklIOoCihoHQ8AB2GQhgAk2hIcCie1QKEOJ2OCKpNwj90u8DIxyTKahOYxfHKsGzABZLgArbSUN38FgATwNmAA2iFeaVzhRtJzOBE6L2jfQrT4WE0UiwZci3ZPICRMiRzGt5qsUHrLkr7dqAHx4nAyAD8AApkbuIvuVRrtRiAMw4mQASgAVAAFVXHDGnjIYCYDee4Ho+Wo-n+AFnpA05gO0Iq8LOewuNA8BTKQ66bm8eygXetqHpBv7HIBkCIck-buihTqZGhGzynya58BuAi4bR5DaJenHXmse5ofAX48fhlwCIuUJYO+75wZOFFKFRIq+HOOgeCQoh8PRy7usxrFbnhfF3nR0AsGAAC8plgEB55gHiwFgNoHi8belxGSw75gMcYAia5MlGnJjAKXyNFQGajE+DpOHbq+MifsJBmXAJX4ORQTl7mJgjIscknHJev6fiJyVqRpxnSfB-kQMhyntphq7YWx26AZ+yWpXeiU5XlBWqep9HSYGIoALqMZAUScAYWgOQAXvMACc0yQCg7YuNuJDwM8lT+R6FDkGwHiSk48GrmQfADFoNAiL0UDqnwjxvHKMyLduNIRB4mTkWFIWnWofAXZAoVQEmmTzLwFDwPYRQJAo91LXsACOpgsK85RrPA4JvQd1V9Gd317NVc0A5UfQg2DzSZBDc0LdDTpwwjszI6jfXJAzEAUYF82DsOXLjvBgUzsp6VLu9TARfV+nOXwEgnmeV4ieLiAvm+X4kTBQEgfFstQf+ZFle9lWoehNXC3pToy2sGtkeVU6TkwwW+MVDHwULdVG1AdhkFxcXOYlsVuy1okLhlElSb5IoWzzoQ24V3XGVpimG+xUDeXbZkWVZNl2c1ic9R5XnxT52vcw7LvKaFhe1SxkV7NF3tcSJXsZ2r-uZdluWqvl8WR3bpWyTrSk4wbTvx5AjX1576Hvu1redVtUdueRVqDVaw0sKN416IYsAAOrhpGmAyJceJ42vRh7OSdhjeTD17FWFDSBtN4bPtK7KJkpiwHOE5W7wbF0Bi01xiknhMDKwthVNswxf7-34IAsAAE8DyEFvQMBP8-5zVlj-PEWB4GFy-msZBkC0FAL-iAxB39CH4OgRiN8xCcHgJQQAvaMDnxYKtiQ3BZDUHQOYZ-JB7D6F0CYdQnhMC6FQIYVQhBNC8EcIYUQiRQiIHSLoBgrhk5JG8NEUouBgjSHCPIQwwC2i2EwLPIooBBi5E6IxCYvhZitEWKMVYvR6DMGGPAdYjRZDXE-3cQQmB4jsHyJ8RQgR9i3FON3l4oBQSGEhICZY6JdB-EsLUcY8JYBZFxIcQkzAyjImpNMTZOxmSwkFPMcUn+sYCnANCRUtJsCVFGhSRiSpNiYG5JqUAlpHjdF5OaXUpJ3DLFdN8S+BpSF5HDM4b0yZMSxmUQmWkgZqiFkFIycklZrT2nlM6WkvERT1lDN2WeXpb4qllIOQ405rT6knLqVsi54CrndIgbcqpSzGnyKeSM2JDyf5fKmR0vxaSfmDMuYsuZ8lPlpLWaCx5uyXGAsobs-ZsK-lHIhQFeRcCznHMRdi65eyMWgMsfi559zUVANJSMmFyySX9KJaw8BVLgkMqacyhhrKsXAs5XSgp7zxm8taTSj5grunktpQ49lmieWSvRb02sdzcXbJgQqs5KKJXgNVQShFyqMRauecKgVDj9UjP5fMyxJqWXyrSTKzV3LrV8ttT-S1MinVAJdUonVvz3XIrdSquViKmE4r9aMtVIag3avDXUw15qHERueWayFlj43fKjQUtNrSQUap-im6BibMXJuhRmsVXqKWMN9b03N+ilXepgZg4NvT60EvVSKhxTayWluzUA9t1KQ09oofm4lba6lZtbeA-tHLG32sRROxJfai1TtKZ2sdP9Z05JbUa8dAbdXEgbYi3dzaQ0Ho7Ue6Np63nnuuaOzd6CbW9OPb469sbwEPrzZe7pMak0ONffo5dN6zEVv3du2tiq-V3I3c+2QZy-2Qd3lUz9BajH0rySOsD6aUMFKfV+4Y4KMNCrQ5smD2GoObIg8RuDmya1lp-egqjXabLgb9TRsxRHEPDGYz0wFHGkV5O41htjSi71cencqjjg7GWCdWUx+F0nSlkYEzk4DZa11tLoyuzAKmbmAs0+K9T2Az15M0+JlJmn+NDuGCpv1KmzMSY07h7TC6HNLqs4B5VKnzllqrbRv1XnbE+buax8z-CDOAt80CvJYXRkRaE8qsLNmUlheM0IsLCGguYDC7p-9YAMvybS9lpT9GPVmLU1lorbTcu2bAGVgCgXKvVdS3V5DgLqvxaEWVv1ZXWs6LK0l7rjnlVlcy7Bqrrna2DZK8NqVxW-VTfKzNgL834OLeub1oxs2ouAtm8t7pXW1v2eVbNhrKTZtDfI2AE7FXjsFb0-8hh1TlW3fQZdoRj2WN+te5xh7TWvtVN28MD772RO1o+6t-7-XgcybyR9wlUPrtZZmd5vJCO-NI4W6jpb6OVt+uR+WzH3TsdA7LTj0HdAcdHaETj07CmwCU+ezoynE2zvZNU365nWnlVs6p3ltn5OdFs5J5gNnf26DM9Z4T+jzOBdgGZ7zoxzOueVfl3TuXcPhsiJGR5+j6uKEw8Bdru7CuUn67wXk43QCpdm9x3rmLtbLfC8wJbi34Oy2W8N0I13yvhiu+OfBfqAYhrdG2rtYUikfSIKxj9P681L5U3hojdYZRUZzX8IEKo5hLDvTCA4aIuxMZfR+t-C+lMoBPRersC2kAMbh-z33Iv25qbx7ptIZPAQ5yLCZowDvLNF56ARhzUcXNVGlxtvze2LCy66UHjLCWgFpZqwkPLD8GtlZ2Wn4gZfWtu7c17k6AS-dy4i2Ng3FAZtYKh2H8pHyCCJ8Vw4j7D2-Ex7V19qPrKQd85D-HxHLqdsY5MQHtuJnMZMnJZGANZLZJgCPHuK5O5J5EARsB-o0hfnsCXOPnHFFG+M-rXE-lAXeK-s3B1O3D-j1MHIzD3DbLjFhAfs7EPGeE1I5NgYJBPG3M5B3CQR3hAAvIpCNGNH0LoPoEYFvGwBGLIPvIfAIduKfA0DVBTNuNfLfENPfCHnyM-NdG-IPmWgogSoztTloWSrGL0pbgBFLnoRrp7lIgSgqoYXcvbrotBiGkYXiMSNYWcjIA4SFrqkYToXlqYRQgYYikYSYUYeYeoiMlYQEahi4dcrVk0o4e4ehhEaUvEa0jEfInbskd0uEZ4WkiEXYa0kEWkv4dkQUt4ZVr4a6lEWKm4ZUb4k4RkbUakZYq7rYeUUolkbWq0euvUdAgSN0fokUR0d7iGjgDgHurqiMWcgMZoRMQSiYTMWSrkVYqMZYcMcsWSi0fMRro0VkmsRrs4YipsTrtUQcbsRQrLm4qcXdqUU0ocXdlMfRksRer0rcT-IsS8T6s8ZcTmqsVUtsRca4Z8QkeMV8YpoCSkT8ZmhCZkVCb4m8SCWAHMfCfcXpo8a0tcYEvCecd4vCcSDCT0fscCc5mCWKhsTie0dMTiXCaUoiaUsiVlqiWKuifEjiGMR0TgCyQSnScNlYhyWSnMbyWYcMQKTruSQ8eyWchscKQbn8d4lKeggSWyXKQBkKRjgcUqaks8eqX0pqU8WqVUm8VqaKSieKVeiqdEWaWShab4laT0TaQwjKVEuqZKQUkafSSad0gaY6jqa0lyWdjySUXaXQFiY6UkYGTkgqdMeqW7syaUs6Zsq6dye6bUZ6ZsvybSWGTZEyVkrWKydMTmZycMfmXyYWWGs8UWRrgmX6TgOWTrhsTWdKSWQShGWKfWbeo2Qau2SMlmW4q2TsmWbqeMb2TAm8UOXqp2VagcaOQ6cYqOc2caUOeOfoouXQNOVYkOXWS6cuZgCOV6ZOQUr6bodWQGf2fhieVUVuTZHOW6UOdGdmbGReXiJWYeTeTuamQ+QeT4UeZRsMVgLmWKb+QWc8QBcWUBaWQccBRWT+RKVBZGqBU2TBZaQhb2nBc8t2d4hBX4UhQOlhXdm8RhXdk+Z+fhd8ShSMquTgMRQBqRQCuMZRQxtRfaThcFgxXQIRWURRQUnhbubRfuUxYLnxekgJbiSxeGUJeRXRXiBsRJWxTcRJVxW+SJTZB+exRJWhVEqBs8XcspTcXcnMYxppWcjJYEjYcMWjgcXcleYmXcsceMR4WyXUmpfktctpcZQOfZfqaZVUkZfEpEeZb8Z5QSgFfjgZZskFb4uReLsaWkt5VkjkWFW+iFd0i5T5ceX5aeWleeYlbUZZVWZDhlbURsbsjFSUqRvFfonpemVlT0Y5c0vCfdh0dGHVXiMlQ4o1WciYW1YetMk1cVRUk1S0Z1Set1WcjlboYNRrjZQ1XVcGTAuNRQjVXNXcSGotWisNdcosStR8YiptVbrqjtRiKuftaNT4TtctTiWdQUodfCQNfCb1Z0vCRtfCR1UiRdWia9R+u9bUZNZoTtXUWtSWp9T0TdaUndbNZSYDeVRDUoi1eAr9QtVqZriidGAjTDRUgjR1QjRtQjaDc0gjQNQjYdQjcdWUcja4ctVqTNbjVUvDVUqjZ0lqRjR5dMoaeTb9qzeaczQCdteqezVUZzeCfzTtrzb4jjaTa0ljdxQ1eqXTbNeqTTelXtVGd9Q8WLWKsTU0qrQ0cLUDdrfoqLVGRLQpdzZVcbd+dMrOQtbOTLc0rOR1bORtbOaLbOQNbOYdbOerRMrOcrUjaOZTdGKOZbbTctaOXbUzdtaOU7Wzebf5dHYFbHcFeHUkfHeFcHZhqna0pHeLend0qHT6dnb4oHQrQ1Ted7fSf7aUh7UMjeW7fecnT0ZnWKg7dSfnT0dbeXWbdtXRfVT9V3c1ctb3R1b3Rtb3aLb3QNb3Ydb3ZXa1b3aXdydGF3X7V3QtV3W3V3YPWHXtV3aPVHZ3THXvXHQfQnVvUnUfSndMnRePZuRfZxf3ZLT3bxTfW9U-R9S-V9XfZstPbDRJZPbXWffXR-Y3YA7URvZsmvaUgtRpdtVpctbpbA2BXtXcqLSZdMmZYgyNfA4FZgx2ag9TdgyMm3d9g1XUhtXUsg7vegxzdA1zZQ8fcQ6fbQ+fdQ5Cbgxnfg9AqQ-fSrYUewwwpA1Jqw5lcw2rbw56qIzkgNUVeI4UtI70YI7UYQxAyGjiE1TVSo5Mco01SYeo11Yijo2Sjjfoxri0UYzrquaYwbl-X8k1XPX6RYybno3VWo3VdbfY+bpo5vR0W4-6icnVSY3VeYzY740CV4+dcEwLY42neE9CdE7CR4-kfE0lYkwXck9ApTd48JZE5-ak7+jk0ov4yDXk10bEz0dozia4ziWowjVUxoycujco5jQ04ZU0wSiYwTS02SlY+bgjbY7oTiBTR012YM5hXU25Zof054+MyzaM6aTM88uYz03M9aUs7aSs4xWs8xXo+qYY+qYsRMwkxs5gK43LcMxUVs6GYc5eac2I5c5Jdczkjs3JvczZNo1Gcc0oychbco1bd8+1b87o7qjiI7f8+sSC1sWCzrl034l7RC3dukwHbC7Up82Mw8UC5M6ixHYi0AiY1OVi20ni3i1C5QkOeY+uXi4Y0OXs0Odo0Oa40OWo0OfCxc3ozeUS2i4RoSzi4U8i6VTy2KjSybYCzeWo73SK7U3owPco0PVK80ycmPTK7BRKxg3K2TSq9cuk8vQq88q4+vVqyMns9vXqxOYC13eY7PWq3Q+MxJUa+s0qyw3azEw63Exa74to3RTq6lSawI067aTa0omyz-X6xI0GzZIY3JSG3Iz6-0RG2o1A4CzA68rMco-pXo0g8m9BYm0Nam8q9m1g5m8hbm6hem85cWwmqW-q+WxQoY75fG-vbW4ffW5a6i7spW7a424+q26xZ29ud2wib2642krG96+276-m-ib27eXCn-SO3rRO3s7sto7sgOx83iqoyGngE1dbRu3870tuwCx0XuwY+u-1ce-Ybu01US4exNae+qze0W+e0HQ+1jk+88osVe1W3e6mi+2RZ+0cd+zRQe2E6u5db+7Mv+wwjje+wwm+09aB6TnB-xeB0GQhwxih39cBxy0h8G1h6G2hzB83Th33YRzVXgNU+uyjeRzu3io07u9jZR60-R1m7qqRzm8xz04xwW2x3g7R4+9RyiyiSx+tRxx+zx7M3x1Q1xw2wezzaJ3zeJ90quYJ0LbJyLcJ9B2p3Oip9Aluyc1p2c5J0IwZ9lRpzkop1GS0Up7UZBwbSZy87Z0R-J7USR187uz8651R8x-beu8C+5wx750xwe+7d56q3ir7cF9cs57x55-x-SXgKOW+5i-51+6F3W4FzQ2l60uF3J9FxEzl8pyl2w0lxw1l66yV9p2V3wxV8h0V0uVV6JTVzcwVySXV7hw18U01yAy1w53l05+u6K31+K8x5K7u9KyN7K3ivK2N4q0N6xwe7PQN7e1N-exN1F3NzF9yXgF3W+4a0t8lzNxJ2t1J5oZtyE8d9a7t9Aop5fQt46-tx6Td6Vxdwwlu3RSR3RZTSd6FQ9+O09413dwVd97O79+1-96U4D9DeDzkiR3Gwewm3inA7uym8x2m4jxm-D2e+j-Baj3m5jzg7j0M9j9q+u0Q8dyQ8T15eT2J8j6l6T+l7T5l4T19Yz5d5T-l9T4V-j8V8z2Iqz74lu4O7z2k4L7V9z-68L397D9O5L-GeLyD9L-y7L0pYr4jfSbWGu-KpuyGmrx5x0dr-u5oXr0exr2j7qob+C8b1j4imb0cVr9Nbb9x1by4-b8+47+iyidbwRc788i0R76ul7xNRb02+70B6b-Caub7+lv79AjjRH+dlHzz4H3z-HyLsnw7qn6h4nz9675h9n815n0D7n8men5G6H4K7r5U1r2R-KhR9XzrwbzR1b3R7X3543xj6b0TZXyF+36qd3xF53yW832W4PxW8PyJ631T7r1qeH4s+P0H6r0raP225P1E7P6p4v1GP3znZv0n+v4h6v0L7vxn-v-okS7WFGdP1L-X9y8f9KofyX8v2A9v9VVry51b252-3Xw8bWF5-Kj5x-y36b1dov9ZuBvGFr-x7668EW4Agfv-yH6wCR+8AsfoAIoaQCaeX-L2tALn7clv+DDVAblzwFs8CBa-RAep0wGPcSB8HMgdAhqo4Ci6oA5lsgOyZUDcmzA-JsAJl6sC5e9Ao2owLFTW1aBjJLXv13lS91+Bw3K3qNwkHjdTek3KQdN115T0hBXfBQRAIN6asRBq3NQetz9K1gtuSg65DHy7o+9TW+gy0hoIZ5yDsuKg-AVoPtYyDr6lg51o4ISrODnupglJuYNfquDBM7grPvYJz7+C8+3gh5r4P0SLFdBBHYIUr08G9cHU2hLXnD1N4I8reSPXXijxSEm80hbfLIZbySHKCDedlAoQ7zyEwCShcAsoQgIqFICch3vBIWgPd7WU4hWAnQS2yaFMMqhYHDIRzw6Eb82hLgnoUczqHP0uhXggYUfzGHocJh4fXZD7ykZ9CwhQwhXvMIh7LCoe4adXoGk16VotG6whBh0WfA9VdhAA-YU1VXIHCQBDxc4Tj11RXC8eNwpxkcKJ7bDtBuhW4ZUJOEU9nhE-TQm8IoRnCgmmw07pcJD4fCbBwIlfvcIcGQis6XwrfrCJ36Ajhh0I0YaCMM6ojjO8Inov8Mv7giOBiIoBpiMhqEiVh+I2IYGir7kjBu+w+ppWgb43Cm+lI44T8Paa0iLhKJV8PkMuEDNWRffHkU8MZHlDqRbvekhyIMHhotSLRUUfM3FF08uRQI9kQvwFHtChRdglUbdzVFOD6RXDBUY-SVHUCZRdAuUV9z5EYi9RLAs0WwJNEAMrRCwm0UohMJSiFGBowQZWlf43D3+7oz-uyJ-6Bo-+nopkZcKAGui2RIosAb6NUGBjih+w0ctbWfAh1w08XBMZ8PDHfDIxB3H4RgJTHNDXhJdYMWCO9EQjoxUIosTCKzHkD-RSTPMd0hqpxjh2JYtERmIrpJiAh9YgHlWKs7NiCRZYsHu2NbqdiyRNw4QYGlEHhpxBg4vYT8JHqjjMhk47IbONyH7D5ulaRetON5HDjNBlw3VsuOFHclnwO3dcamPZEmDtxR3TcfKJFHncDxCnVcYQPnHqi7xmoxcdqIvG6jxxSIp8YaKPEMCPxIjE8QDT-FtirxHYgCT0UWJ7jIhb4vgTeIHH7CYePwxIbBK9EijUh8E6QYhIDHsi0G6EzpsWmvaVpChlwhyrhJGaBoSehEncX6Uiw41IskoupGcMaGkTzxu41oYxPzHITCxqE7odhMfGcS4RrEysfxI8GCSD+wkkXqJLF74SiS4k7DtJNa6yTdcNwhdsROjaSSO6uqXAH+RRIaTAKM6HYY2iaqLFtJRvXSTOIeJGTzeJkhcZoXMk299JEYrSQ8LsmlCOiNku7CYVcmvE+0dVHGh5OxZeT6h9JXyfiycnZifCQUolkFNXJBSWiQUnyQ9X8kHNLJAk9SfCRqpBTKa4U3pmFJxIRScSUUnEjFLJIJSuxKUiCS5PKbFSYJ1kikepJr4zoaR9UicWZIZG1TTJWklkY1KsnNTOR7U+yYFK1JpStS1tLAAzT7RalDJ0zTqbUMbRT8xpso3qRYNamhUZpIHFaaqOqnFiNppYpaXxJ2kIi9p+otaSiK2kNjupTAqaVrSOmASDpBfG6bfwuk9iHpKkp6UojSluiXJHoj6UhO5JYAfR6kv0V9IwmBSgxM6ILo2jDH-S+pP0qAaDI3FaT4x4MiiboV+nJjIZh44GQFOhnzSMZi0wGVYOskks+0ZLRGVxIJm30SZu0vGftKpmHTYZn4nGadPhlNiKZl0umUELRliofJL5ImWVLJmP8WZz-RtEOPUkjihZ30v0lgEkEiy0J1k2QdLPkGyyQxP0pcTOhXFiy1x8s-kZrNNR9o9B6s55D5KMG6zMZEs81qrKYmmzcBisticrI4lmS6Khs8mebMSnazyu+soSa7P04uTrWxs86Z7Il7Wz2Z3s6-v7K4H2zeZ4c-mc7JdEzo4JZkhCdZOSHqSUJ8cmWanKBk-SsJicpWRLOsrzooZucqMdnOcnFzBRpc94eXOqGVy7sMUuifnNPFaSbc1cwTIuhtmFz1p6c+8Z3J4ndz+hLknhq3OrH1zjpvcsScnOZmxypJ48zZLXJDn9ynmg8zrovL7HLzq0R6DYTui2H7o9J28pqSiVPBpz95J7e9KcPXk5zdCB864R0Uvl3Dr5jk3eSXIeI3ydZJ8pGT4WflVyn5fjM+emK-nYzuSH8ydA-Pxl-y25F866j-K7lHynZm858QApeqvz3xmhQBdV2AXv1EFv4tBViMgXXS75c85BeDQwVLysFz02BWpOvk1SKFVI5BQ1J3R0iqFKxe9HjSPQdS6F589+exyYUFyL5A0lhXDPpIEgXhHCt+WUUEViiuF6MgBbNIkVmD90MnORVbKfnqlVyYi28Uos2nqLtpDCymTQtfHaKPZ+ikSWwuNEKK-Zhi80cYqDm6K8RliovjIuIW2KV5pimOTunenILPp7i8WRfL+nXyAZnijOX6UfJzin5YM-dBDN8XcL35MM1xfwoAUIywlIippEEvEUJLJFgS3FvekzExLcZ-ikBfvMJmZK7Z+SjRcUq0W5LyxESvOoUqQUhK6x5S0dqkswXZL-xjS3BfUtumVKSpnShxd0qcXNKqpT84WdfNFn7oxxwyveQIqnH3o5Z4yhWYMvYWiKVZO6NWaMqLnzLH5+8rcasqE7TLUZsy6adsulG7KG5kyi2RfMvHLLVphyjtscqgWnKyl6ynRY8upnILXuR6d7u8u-GvKJ5lylsd8pnmfKbF+yuxdcsem-KoJtygZfvLjnQrqFT8pOdfJTmwrGFQGNqQIqznwqFlSSvOfegInIrluO6OpNbW4wmFuMixbjDjT4zvof2uK-+YEqbmYrlpqKsBe-MiroqSl7Kh5fioqXIKB5zKoebSvpkAKW21KvwYiqnniqAVgqzmaKttH8qelvKsvoqvIXTFNJbpOFcaS8WfkJliZQ+eqoCWHlglmqrqcasQrPFIl7FNZaaoIbDEhFlqnZQcT2Wqq0lhq3+dar-aOqclYpRRe6qX7Oq1Fvqrtuaq5X6qnlgawYcGoFWeqR54a8YWyR+Xxq-l3qqVdGuAmprQJtqngYmohXpq15JyNVdyTqmAstVZReheMz1WFq0VlauZSiQ775qr55axbnoytX0khpyjO1U0nGntqUlxal1T4WkXNqTl1a0KaWp9WtqrlvagNeOtJmosYFXjOBXYz0WNqo1k63xOky+WzqzFy61maup1r1qZV+6kFbuqJGDqc1x616VrwLU6CNVqvEtU0h8UG8K116g1T4RBmm8sV8icJY+qbXvqNZuvWJc+rLlf9Eln6p1cBr7VlEMlVvOlboQXLyox12Aidf+o7nu8OViGkNehrDW3qql0GmpahqFWAb0FuGppchpaW-qrF4Gg9cRqPWkaFVlGp0fBpVVmSr1yMm9T9LvXyIpZLkp9axpfVlEJ6faD9ZYiWXcaf1omgleJptWNoO1nGkDcJrA1aSUB1kk2bxtkXqSzlYUhDRLKQ3KaUNgUtDdpow2GasN7GnDeprw36aCNqmojeZpI26ayNkmvdTOnwXMbeWzmrNfZoY3uaXFIGFjXlgTn0YEVZaJFVlnSHKoUGgKDFXpgsoEYzVkWi1SkiIl4YtZvml3uFrk1IYFNoWpTYFpU3+aYN+Wr1dFq03U40k05NlcNmiqxae5xWl2aluSn1aDFwWupblpMXpat1rWhzc1pTXtaqNvWmjd1qWHxao5-WwWdpj82VYRlbmDjToi43KYeNeWGZfNprVZZFBhmHqatoS1CJ1B42jZZtrS21o9Zu2g2VZhy16Zjxx2gPpdoA7La8l+268etr03DYHZp2ozdTjopS53Wr2ldYdpa3naN1-2jrYDq630YJKthaSt9oG2g6I5wOrzdNqY16Y3FhWNjWdltodYdVqOhbXVirWY6Vtw2UJQNg2346tt3WFtcTr23k6gNiOjLcMES7NYztpWPLdjqHW46R1KSXMfTpZXM6p1lO4gYTre15ZqW6OszWNk9ai6rNgugHYzqB3S6Qd1OnreLr62K6od8uobfzrPXK6xtD2CbSkiLXA4ZtRiMtfRhan66+Nuuo1VljrWApOF1uknYbrJ1nY21UOGTToi7XO6e1pug5drrdWW6CtlWeRd7ru3DZlF72Ipb7pnU3Y51ZadUlLmlqh6LNwev7eHsZnJ7TRgendZ7raXG6XNketzenrBWZ6+lhevNYCg3m1ot5HOA3cMAMms4sdKSY+aXot3DYL2tehtRLjt3V6Hd1OJ3nkjqpS46quRbya3q93l6md9ev3ePqK1ZYQRZaMPsPpuWN6I90+qPe3rq2z6l1q+n7evol2K4pdzehNdvrl3L6Fdh+tNZXrz2j6PNm+uHZfp83UYYVWWbjN11rRP6pcT+3Ik-tBpP7bCT+6ck-qhZP6splWbjDNW4yOVuMMtElbJgdWiYyG0BkfffrH1CJADvGBlXpg4wAGyt8BhfbAYM3U4OMH+-bC-r5W4GE9Z2DjKAZFWoGD99GDA3-pmHYHrRwmBecwav3oGl2jBkvaJiGXUYptL+sZbwYx34GplXGJbbQYE28Y1tohoneQZWXcGu9eWDBABuEMu6jEShmA-way3DZ1DCB8Q0gZ0Q6Grt8hqfdoYuWaGudKSQw9Ah-0vbJDK+9Ax9qYxfa7DZBlQzvssM+yXDdmvQ0mocM4i-DQKwQxfqCNq7zDGukI1Csf1I70DHi2g2jt4wPq4jde5A87SYxvqX9BOjIzIfwNhcEjCh4AzGLSOqH2MiYvIx7uoyjkf9UG0TFkqyMmHyDHOmozpqSNPaGjeBxQ5SyKNr6WjDWio2Lr6PuGUje+tozLu0PV0ujFGmIznqiMsGmjbBmYyNrqN37aDlC6jHrrWNV77RQhxQybo2Nm7kDrCl-VbtEw26TjHerY3+r2MparjL8rjG7ruNaHyDEopjAOrOMs78DAeo4yVp2PNH0DTpF4+0eAO7MAT3Rv4xvrBOuGfjgxgw0rRBPeGITR+7Q+ZzhNn6vjwRlYzDsf1vMUTWul-WXuowV68TmxqHtseAOHDeMDe0TKfIpNCa1DNjJjHbxpOXHaDPerjH3oZM07Xpjx-A9-KZNHK2TE+5A-CQ5NMqqTvxx-RAr5N86iTAuskwup5PgmJT-Rlk0nu0PnURT8JpU74a1OTGdTqJgk7MZlOhGDTixk08sfO0P7ntAWi08Sf0ykmTMYWw7RFrcxRbVtMWwzDiqcxiblMSWr09cdB1kSbTGhn09ycW01snT+hoxDphcwabJtLEl0+KatNh6kzS+lM-dw9PymwziptM01oDOqmzs7mIAw6ZoNBnETBZhgxmcCN5n0TpZujbWaL0hmEdq2ng6Dr4PKYBDrZ+09tpENuYxD52iQ9pikO9nsji2uQ4dp23DmKdBZrZZOdfZWZ9xs5vbuOcjMWYzZi5m7Z2dFPLmLD3Z5M9OcBMmY6KuRSWZmcm3OHBzyp-s-mfe2eGLzox-c9qee1g75z0xp84afbOYm3zppzc+adW3RG-zKO97fEe0yJHztfi0HakcMzpHlMmRmCyOcm25GQL+RkzIUagvFGVypRpC+UYgsM7nt1Rw7bUbgv1GgL3xhC4mYLPEysLdyvC-YYAugm6LvRnC5CbIvQmozJdKzKyw4sSqiLupmi1WbAvvmmLxpoSzfp4uRHntqx0Hesaku2mRpXZ2bbsZkv7GFLTegs8ccO2nGNL5xjTLwsMxO7tMo0vS5yZ0uhnJtzxoyz7okuCmVLxFxbYqLcwh6LLPOtSwee23AmnLPKpS4xfO26cDL15uy8Mfe1RkoWclx8y5ZP1eX9TkVjNR5YL3KZsTsVrg4dvxOg7CTymHeW5hr2GZyT2mSk8ldUvvaW92V+CyZkZO5XkL221k5lfQsaYB9VmIfcVYg2lWVzK5AEdVdsuTaZ9qV8i4Vb3O9XUzBZ+KY1ZM2DXszo15i81dYsWZ1Tw1tPflbCv9XeL41pXelcEvnacSn2iqbNdxOeZLTZ2SLM-t2u2mDruRA66DQOu2EDr05A61CwOtFnkseKrLJFkcqRYZakWKXJFlOtwHosuF-a3XJ+vvG8sYWfzKRYSxYGAbzl6nGFnOtxUIbnlvTGFjesC84bRi2tBlnus6IMst1vKrFgrOhY5h+Nta09aUko3SFaN1XPtZbMI22z9GcCUmwixzbabPZtG32aesDnYsQ5lmyVeSxjnPME5rm1OahszmBbc5hm6ZYSxGyxbllym9ZaMR022dPN0G4rZ3OY3ruUt6izLdlMS3Tz2tkXXzcvNs3-LlWeWzZpFtzX9bC1oG8+fVtRXqbRN4bCbbitM2lVztpsw7f-Pu3ALQN4C7FlAtPXwLCNyC6Fmgu03YLod7m5jcQu+2Krkd5Q97ZqvZZML0d7C4Hd+tQ38LnmQi+HY6sJZGjaNgpcHb6vx2Br6d2i57fovl3vL-tg25XbXU+Z2LEWTi43e4vZ2lrpd-i9XZrOd3hLqd7873d-MO3JLCN6S8PeOtG7R7KK2LMwoiyHHPM6luexHblvcjQsulle3HeNuGW17wZ2m5NKntp2gbrxtGzPz3s53ks9lo+z1YPtF2N7rlzG+5a3sjWobcemezXf2vqkZqjohpSfc1OD2W7E9tu1fY7u-2u7wDnu09YSsP3xL+1lKwjbSu02MraNrK6FhyuxY8rnmak8g9pPDBfhBuDG3LbKuoOY7+D9ewlnZMRY6r5D8W8ll5OYPpbUNtq4g9jOkOlbmNufZQ9aP0Pb7xDrW9Q51u8O9b8D1+5w6mv8IZrtDn+9A7-tPWCpPmIqew66XoPPzkjvu9I5XYDY9r1OarIdcKxBadH8loxFo9BpaPbCWj6clo6hZaO8HtOx6-jt9PqOSHbWQM6VjJ55JqsRj8M2WmqxmOGJ9j0+31hYcGPwbzWCrajqq2uPYbwTvh-44EeI7kbkTkR5gEGxWOu2JZ5x1I9sf+G0nQD0J-bZyfzGMnKjgpwPdR1U3SsNNxHR2Yqf6PadzNzx6zfx3s2xsnNup4vZqfaWqs-Nlp4LcF3C2unot5rAuaaf726sF2gbGuaGd+ODHZhvp8qJmfWGOsthgZ2XZKdROpnY1zR28tccfKtngVnp6k4afpOVnEVqp9k42e5Ozn+To5+EcKyqUOsHt1HbEcR0+2xsft-HQHdKxB2BsIdp51g9YpfrCsUdl50Q9p2oXms8Sr58Zaqx06IXTVtrBnYBey2QXTDuFwE6Rcq2DHlFmFxrc0edHXHQuvF+s8F30s7nRt9nQ3bBf7OHnhznF5k7eevmqXIDhl2A7peFOmXUDzR0PdKwj2uXtps-tU9YqKXEd095rLPcKzz2xXrTgV+075fMmhXDj7rJvYGz3GlXVDhV8M-Z2H3PHx9sbJ8a1eoupX6L2nf8dcfbMOs99lVxXdR3P2RXQjwXe-bNe7O6swVh15bade0urX9Ljl+c7tdKOvXrLv18U80cwPSscDxHQg88dIOBsKDsbGg8KwYOo3vzxJ-SdccEOY3wL1ilVbTcHaI3kL2PmORTfqu2sATDrAw5zeTPadXVsN5fbqySnmst1Et8s6DerOK3hLmt7a7bcJOqsYjhN-eabeuv2dMjgt6c8F2EK63vrkdy7ardu2zs62FXpNmtNZZZ3UuWd7kVneg1Z3thWd9OVndQtZ3yTntu0-WyOV1sMtdbMu5cebZvrl7wtzonWzbufHtaLbHkhOzbZZn9GWbJu7CfXueHt7og2Wlmynu4nB2Z3O+6oPfuJH1OE7Pe-deQeCbwH715VhOznvJ3i7im5B9KeTZyni7yp9h-5fblan77+pzO8af-vmnhHyV-h8PedPyP3TxD705o-9ODsgz0jze7WyjPH34zlj+W6jDTOGPb7vTJ90ht5ZBP0prj+mc2yOHn355pj+2+OzbOJPjruT5S-Q-UvhP1thT8O7o8IelPlzlT-67U9qPH39zyD488XfPP-3rzmd+88myfOjPBV4T2HYE--OnPh76JXZ9o-HZwX7nxj957CIzZKj-nlq9uSzsufuPwX-V+F8NdRhMXvn6PoF5-drZ8Xm2WlvF633vvGWqX02xZ+U8OfVPiHm8pu5vLrvuZz7m8su5vKnvhWM2Tl5Nm5e1fbTlnHXKu8FeLvhXB2UVwJ-FedeKP52Ze+1-Tfbl9L-X7N+++VePvd7431j8MEa93Zt32r-97q9G8Rfev1b47Ma82ymvn35ryb5a8g-WvhvaX7r525m8+CtvOXxD+f2q8wfhPUZddzZzO+6ebvKH+r9O8g-BvJsobxd+G-feRvH30b-97G4E-xu-vib87Mm82ypuAfA3sH-K7WxkOIfkLqDs6hmw0ODsxb596W5+-Ivb3lbr76t6ERI-I+GPrh9N6GsI-dvwnhBeT8O94-jv3bkH728p95fjsg76n7bdp8KOsfj3xD1tbZ87XjdGjvLB9gAgy1hf9-aPSFuD2OmJfOO6nGL+nJi+oWYv-d323afC-HKwv0X046l+QvhfoNYX7YWF8K+H3MvsL6r63Om+Ht1ukJ3L6-c-YEvYOZt3Olbe66gPEOUly9jA-2+IPQvnG+7+OeW64P-vznzdhJvW-nvjutD0L4w+O6sPwenD-H7w8IkCPN2Ij3L5I-G6yPqfnrziF5uZ-ofuf2H-9no-Z-t7pfk7VDklvW72P0ezj-n7N+F+Lf9fq3w9jVvV+SfiSI8+9kk-t+YnluzZ735jX9-FPL2CSkr8DaV-rv-uiHZP8Zfp-x30-iP-P9e9C-jPq-r2-7vM-G7LPcv6z47ts-R7vnluxz8f5z+AvD-Bf0Fw9i88X+y-p-lO-f90M3Z4Xz-xF4kjg3W687t-lv8Dhi-f-RP2-o27r+FPpv4u+L2MS5Q4GXpAEj+ruk3af+zPuAFT+uukV7vYJXvAHc+yAUv7ABgbkL41ejunV74BtpvswLE72C17B6bXsDgdelul17UBOfn16UBBfkN4MBI3jdhje0ehN7sBU3okiauxuvN68B2Pobrn2nAVF6YAxATgbMB2LrgFAB-ujHqkBYAa7q+WD2Pa5Q4sJioHneuupd5qBAfuQGeuUgXP56BzLoQH6eMgYZ7R673o7qfewet943Yv3mYHJGruoD6W6wPnYEmqTgTn6Q+xuvfIPYmbi4FU6bgXf5WBqrobqo+wOOj7W6mPjYECB-2Lj6BBIgQiS1u3gR36iBZPokEgBuulT6pBNPrEFD+2QVl6eB6gS9h5S72Kz6ZB7PrkExW4QQv7pBWAf7oV8eOBriOUOOCL4E4tpk0EKStaG0Gg0bQbYRtB05G0FQsbQSr5NBM1E0GNBRKi0EsB8OBe7KoTQV0EeO9GE0F9BJvgsFoGUwct444SwdfYpIOOHMHSB2wX+4rB8gUYg44YwR7704Xvh0G7IAwX75E4eNjMFB+twdp4U4YfvcE1B+waYELBMftTgL0G-tsEJ+Z2D8H68nwfYHHBafnliAhAXEThZ+8OCJpQh7ThCEE8gKAiEkSMwSX4whkLsiGe8SOFX6ohQXjTh1+emJiFeASIbx6EhdFH0Ft+uISXbghXftiFO+RzNJ4dBA-lSE5BAIbeYsh5tsCH9uFOOp4chTBnyFyqAofaLY4ElDLREhawkjhr+lWO3T6E2OFv6EhO-uCF7+3wQf4LBR-sNgyhexHKE9emoWcTahsrvDhX+HQTf5qhGIdC7GhXAUcwv+hoW-5WhUQaThf+poXEG6hnQjMFDkXQbi5IhSXm6FHBwwC6Ep8koWcHHB5Lj6GM+0oeMaBh2gQCEoBkYSH42hGARTgVe+oTgHSheAd8EEB6Ya0Hj28OGQEAhFAUThUBGoTQFFhOofQEFh0PprQohHQYq7VhGIRwELB5lkiE8BhIXwEth9oUcxCBDYfj70463jMGbeTYXsEU4sgUjj7etYRNZDhQYX6GqBA4WGHbBmgTOEAOqYboFLh+gSuGGBmYcYFzhHwYSHmB3wZYEAh1gfDi2BCwf94nhsvuCHOBZ4a4Eah4PjMEeBO4RWE+BV4X4E3hGIQ1ZIhIQUThhBd4baE04wpkjgxBB4d2HHBCQR0H1uAEYOH04sHBBF9+r4eOFQRk4aTj0+X4QUEIR3IWhGLh2wXI4fhTwRhF1mR4W8EU4dQaXqC+iuAu7N6ujnpic4g+tL4S4zpuXqumFEaD6c4Kvjzhi40Pmzgy0-OOxEBBTOFe4c48wVRH-WJEb+Gi4vevGYMRwEdXo2+3OHb6SRDvinz0h0uCQbyRWQXxGIR-FDAEq4qEdpHoRukZhFCI8uKDRK4PEeuGyRhEXzhR+iuF8Hc4cfkzj-B3eozZURKftPpgh1kfZ7uR14fZE9eHFN6YS41Hs5FF+IuGiHN6R2hzjMe-kZaHS4NfpFGA2nkQrZ84pIa5FSRwUVsGGRizuFGQRcuD36ZRsEd5HwR2URpHRRWkdXpj+rOBP6l6vIeXoz+lUbhGFRCYYlEWR9USmH16Uoa1G-BhkfKHT6ioYrjKh3OKqFUR6oUzgn+zes57dR7Tl+QSas+kaHTRCdpNEVyEuOaGzRsLnzjWho0aJEf+HOI6GDRKUYLh-+i0UkHS4noVtFKR80W7Kl6EARdFFRZ0WPLl6cASdF6R1egV6s4MYVdGrh7UQ1Fy4SYb3pVevemmHc4GYQDG2mSZE16s4uYd3r5hEuIWFM4xYTDE+RZYVDEcRTAbPo1hKMZC4gxWIaXqNhHOM2HT6rYXjHth0uJ2FURjlljFpRfOP2E4xWUdXrDhZMXlEQxsnoZHKBdMSnrN6zrn9EIBFMUgFMxy4fXr3eLMfhFsxTUTTHbh0+ruHc4+4d3qHhzeseFURp4XLHnhiuJeEKxXkVLE+R94WLEcRT4SrEvhTOBQ6l674RzifhEuN+Hl6EQZrFm+7xPRQGxu0dLigRs+uBE2xCkYLjQRTsVXYyxjMXziYkrOMhEmxOkdXpFBveiUFmxvMYZGjuRsVUFhxwsSLjERyqI4SOUjhDLSOETuEn6OEoNI4S2EjhNOSOEULHER+oRhDNReE+ceMGm42vmdjBExcUEFe4gkVlhGE2ccsF6YluJXFN+jcUE5xxMkZViW46cRE7txSkZbhJxbvi7ggercSVHIc-sWPGPRE8QZE6IruN3F1R1cZHEzxHBqXEfMvuP7iLwgeGQA7Q0CGHC-Qn0OdAoEMhDHhQADeLTCJ4zeC7Ct4aeBYAV4AwBwDcAeeAfFOgheFDD14ceGfEowChAdAcA6wPAC541eE-F8IdeFKCRAZeGjArgVeLwAR4teK-Gww78UjDnxNUCnht46eBwQIQQYJwQgAcgEAA Open this visualization in the Vega Editor (although the link is long, and may not work with Internet Explorer)>++@+let trans = transform+            . aitoffTrans \"datum.RA_ICRS\" \"datum.DE_ICRS\"++    enc = encoding+          . position X [ PName \"x\", PmType Quantitative, PScale [ SNice (IsNice False) ] ]+          . position Y [ PName \"y\", PmType Quantitative, PScale [ SNice (IsNice False) ] ]+          . color [ MName \"Cluster\", MmType Nominal ]++    spec = asSpec [ trans [], enc [], mark Circle [ MSize 9 ] ]++in toVegaLite [ aitoffConfig []+              , width 570+              , height 285+              , gaiaData+              , layer (spec : graticuleSpec)+              ]+@++Since we <https://sciencefictional.net/2018/04/23/we-will-control-the-horizontal-we-will-control-the-vertical/ control the hotizontal and the vertical>,+it is possible to \"rotate\" the data to move a different location to the+center of the plot (this version has Right Ascension of 0 at the middle).+I leave that addition for your entertainment!++-}++skyPlotAitoff :: VegaLite+skyPlotAitoff =+  let trans = transform+              . aitoffTrans "datum.RA_ICRS" "datum.DE_ICRS"++      enc = encoding+            . position X [ PName "x", PmType Quantitative, PScale [ SNice (IsNice False) ] ]+            . position Y [ PName "y", PmType Quantitative, PScale [ SNice (IsNice False) ] ]+            . color [ MName "Cluster", MmType Nominal ]++      spec = asSpec [ trans [], enc [], mark Circle [ MSize 9 ] ]++  in toVegaLite [ aitoffConfig []+                , width 570+                , height 285+                , gaiaData+                , layer (spec : graticuleSpec)+                ]+++{-|++If we want, we can treat each cluster as a point, and calculate an \"average\" location.+The following visualization presents the average location of each cluster, where we+calculate the <https://en.wikipedia.org/wiki/Mean_of_circular_quantities circular mean>+of the Right Ascension values (to account for possible wrapping around 0/360 degrees).+To see the effect of this correction, we+overlay the simple average as unfilled circles: for all clusters except Blanco1, which+spans 0 degree meridian, the two match.++<<images/vl/clustercenters.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEAWCmCWBzaAXSAuMAmAHAVgBpwoBjAewDsAzJDMUCCGWAQwBNYAnO4SAGxYAjWHwCCFRH1h0ADAF8ijKADd4sAO49IAZxScyAa2mYKAVz58FxJlRYlYaTL20AHO-AmyrSyCwAe8No81oyQbGQAtiwedLZ82rCKSlACwvGxLPGJIUyInPBsGVlJPijwKFJ0ZhYloWUkBkGYcQkh3qFSiLAUhU6QZPndjlCCZCgokZAEUGUVxmDVlsTtYSwoLME+ppx8dDDjLtroAPTHnCzqAHSI5dCmgqYJnOQUKEOX5BHHACJkpogAIW2RmO0GUsEQLGOUV0XFB4MhxzYayhkPgLAAtCxMQA2ACMOKxeJkGPWgikeJYlwoZAxcHYXEuKG0yimIUgVAGUWGDGSkDcnASm2STAA4lFEHszBFhNxaj4AEqiAD6AEkAMIKgDKUtMMq4bJFTBcfD8uv1cpyoW+AFE1ZqdZhINLZYajZBYMqTWanS6DVa5G1lklIOoCihoHQ8AB2GQhgAk2hIcCie1QKEOJ2OCKpNwj90u8DIxyTKahOYxfHKsGzABZLgArbSUN38FgATwNmAA2iFeaVzhRtJzOBE6L2jfRfE1SGRtEqpqRMiRzGt5pByNoABTIlB6y5K+3asAAKjAAAVVWBjmA8TgZABKSDtEW8FgznQeBfTDfL1dvPZtA8Hc1n3Q8NWPM9L2vW97yfF9kn7d08j+FxBHbcdIHVPhHjebgAF15T5FhEDyCE13HK1X36Fw9giVgKEXac9k3JUZCYmgRF6Wd51EZ8iOoshaKdeiWEYn930Ar9RHYn9OL4bjPwoBcEMnXghLohimMkp11H0CRlXOWSoHkxTwIdfiqMQmjNLE7SPw4EhjI5NQFL2W0jx1QNJwgfCrNUxgkJFZinSMt1J1-PgVwEACnRRCgsBAvcIkuIDlJkghd33ViZIfU9YJkS4ZBgy9IH8gT6CspgdJSFgZWRcL3RIP8YvXLKUqMgA+O8ZAAfiS-cjIxABmHFHxPS9jgxHqwEwdrLiMibVSmnqysnAKIDfD8XGgeAmOaqL-za0CUscmQluOVaNsqnyoBq3w+B2jYKqYA7ooouLNy3L75p2+AHxPH6TsuAR6qhLAHyfcqrKC4iPzSkhREe6BnqqpdDtavZ5syJ6wAAXjxsBit629ZrANKBpSnGUbym9seRjZobUtGQqgM0XvR97YqgUbzqB5LLj+gGKfm0HBGRY4IeOLdLxPeaEaRp6ofWiqtr2DCfzeo69h6k8ReBoXpdl+WPERhn4KtQirUgKJOAMLQgIAL3mABOOMZnbFx1xIeBnkqAKPQocg2A8SUnCsjcyD4AYtFMvZsNwg0fxQT31xpCIPEyJjOm6bjFmuyAfSnOOnXZqAk0yeZeAoeB7CKBIFA9r29gAR1MMTZjWeBwUsiKML6EuoA18uDqr51a-mFpYEbyAU+bp02478ou577zkjXiAENh2fB2HLlKLU1nI94-aWo+njKYPFUIK1fLoJvHr4NVo+0u-TntadfWBfMyCLyvB+4K9yNLDHwKFTBoX7mAbsWEcKwgIhzXwpFODkW5hOW6U4NIiS0hJD8OVnKD2PipDmm0bJYLsjgqS6V8GuUUq-Pi10lDqWElAUS4k7ofj0pQRAhkWDUK4nsH+XliEYOYTbbB7CsawCchxGh7k7Q32fGjPyKsYYs3umFBBWtMZxXWAlS+dC4zzTwXlM8PUiolVVGtI010QGhHumLBqmiz7c1WALThBkuo9X6vNdx3Chq8wBpNaa94yY+P0n43hF1gnsSZsAo+f1T4Y3Pq4-cZ0LpXVVmoj81NUa3Uilzdcdg5zfWKb9XaAN+b7gceDSGViRQ2KyZQs2T1GrBS0ck+muMCZEzACTPEZMv77hybTMAnSUZ1PXpkvJ912Ys3aS43mgNSkG3KXrYCos6rixqUbVUctgYK3NhMpQNij7D3yR-KAutBkpUNjLXZJsg6KxpookUVtgq23tn0J28wsAyHdrPVOLFfYkEqHJeAFhYDcSngHbowdQ7CjaVHGOA9ZFOgTnApic806REzrsH8OcehVHMJYCqhdY6orZkxCulQ+g1zrs0TIDdk6AoXu3V4y8yir1JZA3gBCznUrHnSyejLp7MvnlARe7L1icukBvRgcqt7Wz0GJPeo4D5xPujlRJBSWLLO-tfB0d9-4FSfjDF+0ltUXKUpfQRRqYKPyAa+FmYCIGYXRXhSAbyfKILIpCVBaMSGYJYeIo+eCZH8KdFqhhgVSHBvIRIz+0k+FuUTelR1PkmG2TYUfXxPDk1mQNdqdNh8g1iPjUfM64aU1QA8gouVrzYlOumR+DRcznGFN0YlB5bFMrA2MflMxxUbylUbYhRpTpqmtL5PM46AtPH3m8cDfxY1AnLWiaEpdkSgmrVHYw+Ju1LXaKgPNNJk0MmqObXsHJU6fAzqvV9SpNzVmPpBpsiWENlbWKmd6+6ByWlOKSS4sZLB8aE2JqTTA1zLjDJgsBo58rv0RRmTe0Id6nSLJfULNZFBL7VMlg+HZeyBZ-uebumN90zlocufebDl9bnG32abJ5LALavKIjbFgdstBsCLjgCSVZECMQnbAKgaAxXrjeH4NAMKg5kBDp4cOEVyDR24CiiNUB3VJybtijOFAs74ohLnIlFgC6SZ5C5dTMDE5ym01KHFendgFyLryilZKfwCq0EK+uorbOsqXtK7usruXkss-y0enmJ7eZnli1ubLO4ypeevNotRt7KqHCOMcPYL0-o-JOgDOqnSiwkN1BduGJAjRXVEmac1gZ8AkFV+88HN7P3ugkzW7asa1bWOkxrDTL1xQZih16HXPrFMw8+vVVS301M-fUxD7pf1McG-lq1wHQM9L6QM9ZwMYN0x24Nsjm1x2UpW0eyAGHJtPv+rRjZYN8OEYec00jKjD4UcPckq522Bb0fuYxx5hz61gC9T4D5Ds9CGFgAAdXDJGTAhU8TufB0YPY5I7D23E3sKsFAgvW13BsRT7plCZFMLAGcaDD4xToBiN2+KFNgGidG3glPMDU-+XVsO9O8R4HkBzJnawqc05SHT6avzGdtmGKz2nHPWdi+Z-TwX-BhdjVl-zlnCv2dU+GjztGfOJfq7p9r26uuBds7p1rlXevTcc+V7z8XJupd0Ddhb+3QuOd4lF7buXkvXd0C54bjNdu1dW99-eZ3LP7wO5Zz1MP9OI8+6j9zmPGI4+K+l+7-3FPVex+D0HpPKeNcs5tzrwP2fI-0-N57rPyec9EzzzXivxevf57p0Xo3Jfq9l6d5XiXze3ce8b1X3vvvE-d6p0PzA0fR8s9jGXhnU-6cz-j5zkfA+JeL9T1T9PSf18F-lxnuJXud9K-39RQ-NeRon+smfsvl+93X6Xw3tv9+N+YFbwH5-u+u+r6p0fvvt+Y0f505+7b416T7f6F7n5gFP5V5jSz7AHz4YiwFL4i7-4kJe5IEv575J4YG76IGoFTjoHn6P7v4wE174HG4QFl7EGZ4S44Et7kHt50Ec5f7QG0GgH96sFU5MHD4MGEFl5QEkES7c5wGh4IHCHIHwHgH07iGYEoFJ4yG4EsGCFU4KHH7yFEG8FV6qEc6aFCH166EqE15v40GGGd4GEs7aG+4cHKEWGgEr6cG2H8GiFSEYi1iQHOEOH05uFwH2E2FeGQHWEmEs7eHIFKFBH+Gz7GEH5V4hGyHUHRES6xG77mEREP4pGuFGHpFJF05hEJFU7ZF-5J4FE8FFGgEeF+EX4iHpFa4+HVEBF1Gz65Gn5V41HIFRHNES6tFxENFL49GYHxEdGa6ZFJ5dGf59G75b4IGjFAG+HhGVFL4CFzG-JVFJ7LESGzF5Es5rGyGTEuHbGKHpH7FqEIFHHS4DFX5V6nFeAnH6GrHDE3FmF3H8GBGbH05XET4bGDFbFlHpHEgrEIF-HrG-H1FJ6AmyFNEXES5gm4HtGQmb4aGglkGIlUHAll6wl35V7Qk5GokLEvFfGc52E4mYGLGvHuEpGQGfFwlw5wF4lUlEyNHkmRGMnIHnEYnDBInz63GclonMmYEQlsmyDPG8kTGUkCnUkLHlHhFYlp6SmvHSmb6ikAFZ7ylR60lim3jn78lKnDAqn07onam+4Inz66kpG6mskGkT73FSG6laloHKnsGmmEkx66kkn4nvGc6ylukUkpHulyHz6+m2kEFZ6+n6l2nDC+nmlhl0Duk+lclSHumhlBnhk16BkUHYAOkx7umSGeFZmel0nTEykpEFkKlFkgnz7Fm57lnn6JlpkVnl6lk34x51mRlJl0B1k1kl51mpmdkZlVn8GKlRmYB1mul0nFFR55nqljnL4pFTl+lSGzndly6zkdlLlGnzkcnrkokx5TkrlZ5TmLl7m9mbkLEDmtmYBTkjnqmWHjkpHXnTkx53lzmeGPkHnDCPm7lvlrnPkbnflbnz53kflRgpm3lHm-knkgVOEpHcE3kx7QX3nz5wVPl+GIWvl0CIWAWv5fnIU-nYV-lSFwUYVgBwWoWYVCmwVOkIU-Ex6-6b4TkWlgA0UJ4pGMWc5qn0UsUy7z4cWEUcUtlpksXMVxmeEsU8XAXUWgV+EsXZmSVUXz7j4ekpHyXTSnlplKW7GeFKUkVgBKWEVKV8Ul7yWKVCV+HyW6ViVyUSXhHyXSVWWyVSH66Fkx4OUllOVln2WakpHOUQGuWz76Vy5eW17z4BV+VZ4BWEUBVaUBXqV+FRUqUl5RWh5WTKKTLWywpybwoE7BTOYWbVpua+YSpxYcqBbaQBAzj5ykocDrDgoha5WU4Y6+j2ZZwFw8o5WKRnIxZ+ZSorzSASSlXGZLD1LJZ9hKq7wZbqpNo5aY7TZDbvxnZFaIAlZ9RlaIAVbjTbohI1YCzs4NYxIvYarbQHrtaAazpTYoA9bsR9aTUDb-ptrHX3pjaXaCwTbbi3ZbL4azYpXMz9blxLY3V5JUYpJUwMzrbgb9KQZfZDLmywb7YtKHY3RXUna3UFY8xjRLIvUrLXZQZ4ZSx3JEb7gkYsZNZgAnJvZHXI2QCfY4ZlL-QPZ-ZPaE2A7A6hCg5fJI5Q4w6yCXAI7lxs0o4CANCYosopAeA47BR44Ip8hE44Sk7jWvHe47F0WDl75wGxhJ4BXTSEXy24E2Vy3q14huFq2QEhWW40npF63EiG1wF-KW2hFm3n6K1nnK3IGq0IHq2a3q1xVe7q0G2u1YVzHq1sVK1a3C4W2+2Nlh0LF21l6B2O3B0c7G0u6YE+0uEBWe1V5hVR1L4u0p014O1plx2O6Z3EnW0R3Emh051kWl0TEJ1B78HJ2eEF0fFF0THu2gHZ0N0JXpE4B8YSF53t7d0q1d0907Ga0D1Al57D3a310VFj07E12x6T0h0x352z3a3l0N2r0h0l0uGb3S5aXJ6L3S591N6H0-5D1MkT2z5p096n3BHn0sn32yHL39230EmX29Hv3F2f277P0n14Ub2v3T1zG71AXf30FgMc7t0z2v3H2D6v370gOWmP0THr3QOV072v14jz0H113IMzF4Nu6j2YNQPAOYOwM944j-E72UMSEkNy04A0Mj1d2MPa3X1j4sMh1AP0McNp7YMMOm1548Ob6oPANCNR7b0b1iNYEIH8PIHkPsOz50P4nJ5SN4GCNX3MOz5cPKOyPdHqPIG-2D6qMiPcPh3UP8GaNL6GMUP-0z1SPaN0kqNl5sPh5SOj1SNKOOO6O77yOuOPEyNSPEiWNl3BMTHWMKMLF8OBMOPqlOPgX6PEnuP8GeOxPeNAG+Ox61hUMb1ZO0Nd25NMN54FOsP5NwExP0XJ7FMh18NVNp7hPh61PCOlMSESMz2NOVk73tPZ5FOKPNOyGj1dMYguOZNaN9O4E1Oz71MjMtM9Mf0yNdMmM6NdNTOVO2PANdPlNB04BdPDOrNL4DNl4pMVPbNl4ZN7N8ljNAGtPrP8GLNeMLMrMnOROXNu6bOx1PPEm7MfMt0vO+5HNbMLNnM4BYDZMz0gt5N57guFMyNQslOQtlNd2wvVOIsCMwtwF3OpNItp7XP0NYsm7wtyMovO1Ev9Mku4FfN4t30Et6NosGNktb3UvJGMtXPMsc6POUtgB8MctvMr0csUs8mst0D-PvMctAscsIMctBOCsT4YvHOSvsv8Fcu4PSu3j8sLGj2SvCu8uQV16gvAOQFav92QGj3em6sSE8tGtwF8NuUb2QGytbOQE4s6MeVmuyFAvn6GtN7Vld3n5fPn4Wteu+U+uTPBszMyM4X6sWOus-2hv9Gxu74BuD415+sCvhuHPxt07uv+M72gFOteOgH2vvOWX0OgHWvKtpvxMVuJMZtu6etJs6sIHRiv1z4uFNuD3b7NsEjpFtvj2NuduJtr6dvYM9s7ErMjtr3dudt5uxPjvC772ztH2Tu9MdsX19saMrvIEDs-7NvDvNtjtTsbuYFLuR2Hsxuntm7HtJ2Xu767MLtoXXt051uDunMPvMGvuGnvsyufu3j7uKvfv63-u3uYOa13sT5PvbsNutvGNnPRjGPgfT7GMgfGO3vGNbsIdWvdvGNjvGOFv52wdW2YcMnb6qMweqPwcL6qNIfruNuqNocUdBvEchuMdhtQdmMN34cns0fR2EdpHMdXt8c3s8eYFUdZ1Cc+NifYkCdXMSdu64ft4cfEnYd-tSevMyclFcfqtqdgdacFTb6DOXkVPRj6fkcYhGdwEgf6e3v6d0emf6fDv6djv6dyeH76fTuGeDPzuDMweDMmdmdtHduDNWejN6cMeNuDOOdW0hdzOtsLMBfcdRdxsJcJtxdL5Bf7MpeYG+ddPefZvsexcZcoMFdAERfPNJdAE2d+efNFeEPVd-O1cT4wccstvsdNd4i+etcgete3utcVetfDutdjutfOdV7RitdudB2jdEeNtNeNfLvTeruttNfdfBfzcP3b5NeDeRerdHvrdRvbdnv7cXu7dL69fOPdscudfpvHeYGzdL7zuSvjex2TcLHDdr7yvnfKeHeqfXcikfeac-dAHteQfsdkkgHtuNvGvdumsQ8Itg8SHDs2sVEcV4ivdn0Edw-glQ+z4wcetY-+cY-kt4+yEVd+1y0cVjuOsE8G5U9u5E8HetvGVzEsUk9nc0-3ts+YC+e510+Scw+R08+ycC9WFC8T4I-lsM-9ki+3ggdt1S8GdB04idtnOK-g8uEq8SGa3q87G7Na9T3pG6-IvYGdsrMG9p6o+F5Tv6-Nv72m9j5W9zdq-Nua-Ns6-Ns2e28s7YMe9vH28scN3e++9f0IHe8m+v1e+AOB+CdG+puO9XfB8wOR+8+x-8-R8veJ+FHx+ffJ-Enu+YOu-8HO-JPp8h76-Qel+q-++Ifl+9tq+ofV9z31-a0m84eN9b2t973t92-YFked-eXB+qM6+0e9-1nd9Mf99be19scVE4iBPD-N9rNy0z9l7u9SOD8x+V9x+T9L7K9SM2+z-D8o8H-z+lfj8LEr+S+j--en-EkmdL8Sn6-6fK-GcP-mcv81-+-Wdv8N-YEOdf8Ts--o9g+HnP-sLif4O8P+C3CAcgR16DN3egzL3uFxAHYsAB0XKAUHzV7LMkBbZLAeeRwFgAYB6-afl01v7Zc8BNvfLigJCaUCwmeArBrQLgEX8gBBfWgSQOB7T9WuyvVrrfw6768uuvA2HsHz678CJCJvIbsIJ2KPd86OIJrjbxm7iDcC3AyAewOo5q8mu7vJrl7w27yCGWggqfnMWkF7dVB8XXQbxxMH8czBUfCweAysGQNtBHOTgbl2UEp8bBvuc3nqXe7YFJWmg8Xv70lY69JWmvTVnYJL7YFQewfA1vr0h6hDai0Q81pEIw6xDR28QiQm4LwKAC1eLrcIdj2SGyFb+3rRIYTwKHC53epPZRohRN6U8shqA6frmyKFsschu+L3jXhKGs8qhwnBoY+w6H2CuhhdOoR+z6FfsBhP7HoaLxGG3gWhlbDIcwKGFtcxh8vWOngCV7pFFhFfCoisI17LDO2uzdYTsRs47Dta2DfYUvU2HosThLTM4Zj3kLNszmRw6XCZ1uFcELhhQsQm7yeHC5Dhe7N4cgJeF6C5aDwy0lcOMEuF-hnLL4XQD2Gv1thr9TWiCPuEJ9ARd3MEUgwRFUCfhuJJEbeA+E+C1hefDEV2xRETE4RbAuYngDL7yE4OywqvuSJiFiE6+1I+HpSNRbAiW+9IiQYyNtqsjcCNwnvpyOOLMiVBDdUkSt35FrdaRY-EURIN5E6EpRhpGUZgBWZCjTBEo5LnKPwHsj2hqo+4VI25GOCSR+-VUYfwNEKjAmhw6JuqN+4GiYRgTLUcSL+GP9lhz-eQvpxhGWcHRAg4EXZzdEiCvROxVIXgFc4+iDiTo7IcGOJahjSW4Y54R6OFGCj4BgY4XAqNc6RjqeYhWLsmPqHpjsBmY3AdmLVG5iXRm-WMS+1zH71-RFjeMYL1zHRUSRCzQ4Qsz2ELNthCzAsQsXuGAtlhHAjsasJJE8D5CfAvse6MFFCCBx3okcb6K7HnCxxQYsQnIKnHC57hTXGEUtwnHE8Vx4zNcQmI3HfDgRHLLcbKJnFAihxC-ZRngG5Z7jMA2wi7ueIYrXibh4ra8VKwPFp85xGfHcVnyPFn8Hxl46YU+Jv4PibhYQ4EREPUKv8QJ7-NYZAT2FG1lhiPEkXaxgnpDBRmQoCSGLEK48wJEYtCQKIgkxicJoolCXSwwna0EJ1QuCYYKQmHi8JiXLCSdxImYFthVpCiaJyImZs6JYxFibTzYlAE-RxbE8aWy4nfcaJVXDib7hhGy8RJDXLIksKKKdsTOtYTtprXkk0iXCSkuITJISEIFVJSQ9SSkKkmISKiWk6cSpOuF6Swxmkp3qZNkK7NDJxQyyeuJ0lP07JOg4yb8OUY2TaeDk+ng3XclZjzJy-JyRzmsnQiApQrEKZgDOY+TMA+9SKRqTCm3hUhMU6sXLUSnYNEpNnRKUFJ-EuTWxcU+YfnVrBkjNJFIoolSKKnKTvJdIsqQyJKlMiKppwmqZOKqmXCmpXIrIjyJal8i6p0AtqbhLmIFTQuKk1Ris36l+8DJUjHqZx0GmUS+pUjVKfYwmn0SFpu+RSR4yWmsSGpFzDaRMUkHt4RpqIqaeiK2lAE5p2ImaYwIOnVsjptbNaW7gin2iiijozSc6KyKuiHpg4gyZ6Lemjinp9Un6Y1JUnACvpbrF6eAI+lKC+pgXEGZuyhk0sAZ4o7yUmL+k7ckZ20oGV5LBlKiEZ-ktGXTmsldNFJxAmGeJxxlvsSZ-QlGdxKJnFcqZbuVKfWJpnqc4ZV-JmX+LJmSSiinYjmd2OSm9jNJ-Yvme9L6nDiBZ30lSWIK5n-TvJMgrIrOJFm5CZZ4MnmdhKFm9SlZ+EqWfDIMljcJZyMsWeRK1nTS1Z1EvWbRJ1mWCTZGouWbvjkmisFZiIs2dJwdmVirZ1Mp2b7lSmSt0pfgu2ZdJdnXS3Z7MzSYBO8nASg5oEsOeBL6mQSsi0E0orVIMnwS45kshOVNxUn20Y5oMqOYrLcm+sM50MpObDJDmays5o0kubrKLmTSK5mBYaYz2SnNC85i0guctIbnWyW560iOZtI7nbS25zstOegyrnV0e5vudKRRT7nMyB5gPIeYHJcLDRpJUxWSdUQUmLzypFRWeYLLlprzqp88+OXMU3njiRilvA+anIbp7zWpR8syTPIsnnyrJy8-OdvPVmrzPh184ic-JTGXz9Zu81+is1PlHd755g9+al1vmWyAFmXIBcTL-nsSIFjsqBb3JPmYNv5mDbBj-MEkgKLRMC0SWAsnmvzbp1RQqTPOKlTFSp+ClebvMqnEKt55C7SYQt+mULiJuC4+avJI70KL5J8yjswpvkjEh+nCgaawuLkbzjG7CpltQsrmMLDZyjUaMeMcYSLTZwixubIubncLmJ8i9ubQqT68LnBqi2BaIsOnKLaZgi8rvordy7NpFvszRXV0UXEkzmw0e6VMUekzznpIxV6bYvXniLPpzi0WSfKc7VEAxjihhbvK87eLM5G8wZprWsXKzglqs1xTwtXmIDfFpciJaRISXoDPFYiqRV0yQUbNAlgCuJcApSVKL7FxY9xZ3IKUaK8l+0spTQJyWDyqlBimpUYqyWmKKlWCopRMSsWcypiXA6orzJnn8yelLiqRcLL6UeLV54sjpfpN3nSyRissoZfLKmXZyBl4S8RWoK6XRKJlfCpZRPxPm7i5lIitZVYxWWYyRl2MsZdkpOW5Kjl+SrZYUpmWQKbl0Cu5Vor2WKcDlxJJBZ7JeVoKHlGCnZazLOWtLxiIdKxaHJnlRCpi0PEFf0tiZ1lpoSC2CRvMTlgrxl8KvxcisJYjF0JiK-Hpio4XYrcCNnaFbCvWVSLKhEKxJeItqG4q6c382ueSuOWkq5F9KhRZStsHorrlJ88yoyvuXsrbmAK18dypP6cqUF-K4Scyu+WirtOrK+-qsTnl7EF50q8ObKpIVy1cAkKipiqooUN11VVCxVbpPlXJyli1vQ4iZL1WzKTiV8s1YsscZaq8VRq1ZcqqfkWr4lyja1W-M1WYNbV+yk1Y0I9X-y3VrQnVecoNWFiKiLq7oV6rUUhr3VPqwruGr5WRr3x8az8bGsZl+rx5ia35QGv+WrE8FmqghXsSIW5qlVzqshYWo1UhqsOhxFkScQEWVqUVxa1CfmqCX1qsVja7qdmsiVWrVG2DLAENNrVOrO1rkgdbsuVVSMVmPayRbE3HUyLW1DK0tYGpHXBqli2ovtcUrnXdz21z46tf3PLUJql1p0hdZMLXVAFNaU6jNUepwWrEbFexOxZqocUnEnF161VUHSwBuLH1wypYl4svVIrnVgM+9Q2tvVNqrVISw4pDK-V3y31hckNbEr-X9rJ1XTEDR-OVWYCwNxsgDdOrQ2zqoNhAj9YuqQ1sqsN9smDcXQQ2bqINlSojdUoo21KqN9SlDT8zo3NKyN6TQ4u0r2KdLVi3SzVb0q41PrY6WAQZTxvfXKrRlbG79VasmUnFplgm01aJpbXSaox8m2yRxrtXOqtBym2DWqu2WSbENqm1JZOo5bdqzx6mzDUsSvHGbW55mlRYptJnabSlIayVqkP43brTNu64Tfut02Hr7NWU6zeYts2WLDiwckNcCs1Wgq9i4KkLbxvzq+k6BTxITc6oRVhaxNk65CRFrRUPEWFQW+ZclstXZbwNqWyDUsXPxjqSV+WoRYluHXxa9NaqmlVavrmxaTNyqxiZlsuXNabuAW3UY1vLH1aY16W55d1uOntak1vWz5aVuPWDaz1rWrNQCRlUN07w3M5RnNo2Ggkthvxftqto0kuFFt2q2bZ21SFba6Fy2utY4322gD1tGWuYidulya1LthhQ7XloqI3bPeZ2xyXdslHTbB1sTR7RqVe3oyLtYfZ7SqPe2nLNtwUn7Z0LB1hqgdq6h7VGoh2uCAdrsqHZRpB3ubjtuIuHRPmu3EMEdF6gEjmoe15rZtBagnUWuO0lqSdZai7RWtBJVrNtNamnUds+1MKGd52uWgSCy0VN2dbavHR2qZ0qaydRKvnRpqDpc7y5FO5JeLt+1s7ZpvxeaSzoa0La3Gsu3DYrvw1U6OtquuzertI1E7nN0u1zZrpz7K7PN2uxpZLsY266pVAJK9bNpvUPa71m2h9bbsi3t59aG253XFuO2frrdSWznb+sd3-r7dgGz7cBtBKgafd92i7XGLD2C6-dmyoPWSq906ak9nqiPahoT2+qM95sj3fOoW2EyY92-X4l033pu6tdbOhZntoeZF6DdKeo3QXpFUB601UeovvXqm2bbWNs29jQCU40PbuNvel3V7ndzu7+9nuz7SJs72+6RdEm9vYHou1NcTOQ+uTSPpxUz7I9bOjQb8TU3d749c+j7Zzoe6gkOWKzRfent33obl92ei-dYNX2gLD9au9fRruO0PdN9PKu-Topv3I6J9Q2j-fgzf1m6z9E2gA23tm2BaLtwWh7aFpAOk7Pt0c5EpTrZ1wqFtCWqA-qoQOM7Od6cuAzJpQOYTNtucrAzaoIPvCiSuBY-SVogN76RdFKvA1VqoMTqMDdKnA5frAPYa0DLWlg4XqIM2aaDZepA6-oBK8Tjt-Erg8PJIO-6BD3migzlJEPTyN6erehvNq8YKq5DkchQ2pJkbD7gGO8tQ-vI0OoGdG6BrZrPp0MKCu6HOow9zp3q87jm-O1JrHosNvarDieuwxVqUOp6nDp+kw3Ths6QizD6XPPCrrcNtaAjhGjw+ur0PlKZ6eugwwKpUN16IjI2qI03q8P+yEjzG7AvIbKGKHYmxO-QdAYqbk68j8BrI6PoKM0L-ek+2Oqoxt7GGSj2B6fuYaqM5ayja+uo-ZOD72Gmjwuro2LqKMS6+jUuto7-LV6MGGjwOio-4Y6PsHF+9+oY9wYmPEaMjOusY31qmOvL9eqOnI+dIWP0a1jhIjY1bpUmZHHGduvqcoYMn5Gg6n-IopoeSnaG3J5Ri4-oZOOGHY6ASm46zoeNL6zjlh7ydYauO2GKm0Go490fymUG3jye2Jshs0n0GAT5+n4wrpeOTGQTt+mE5wbRPQ6ET4RlEz1pxOI68Teij4-EYJMpqnj-+u49IYxPAGQ1xxyddkbVXnGlilxvjQPsuK3HnV9xq1Y8aZPPG6THIk4rUa5OfGhTuBzVc0efX-GWTD8nky9oFOgn28WmvYpCYZPuGxThymU4DqVPjGaTyJtU6ia1PBG5TmJ5VV1qNO4m9T5Gg05-p1PEmLT4hq02NtWIt6zT6R7kr3WFIh1yOkBvwuFp9Osn2S7JukogaDPcnSSlRtMilr9NpapCGKmM40YjPinHa-rD02cRTNU4pm5B8IhGzDOuH1SNeDM7CaTOjGsz-qzwk1pLPTH8S3PGPByrLOmm4zyxis6sYbPrGazmx+iqPLrPJGqzzpls9SfCId6-CXe+MoydeJ96Bz-p6MoGfVIDcfSoZt0uGZLzT6cygpmc8HvoqLi5zvxoc5KbTIb7MynRvczvrHPgmjzuZjc7QcdoGatzmeic9qbvO566SHLcjrbIPOhGVzvBp8-wZHPv6PzrZ-0u2aVrey3z5Jhc5SZ-P+btytJ+iqcdeIO7PCTuvwtcfnyvqELnJycvOdHKLmlyrxtMu8ZQvrmlaoegi9ufCKwCZygJoi4eZLyIz5yp5mi8qaouqmkLhZvC8WbgulmWLupri-qbQvom6L75ni9ib4uRGyL0RrC7EaEvUaBLDekS7sZkv7GoLhxzwvjvCKE7kKo5-EshygqTnX805+itToQqYX1S9Ooy-yfwqrmDLhFx2mwtgqJm0yXCsywVteK9q7L8puXONLcv9GXLl5hy6xZLxy6nLzBny9xbUuBGTLsxukrvx0ufmIrjZkK82ZUs164rtpjSyboSvyWkr4FrK5BbkrQWlacqvK0tqKva9FKul7SvpYKvoX6Ku2sq7yZqu4WDKllqq8KfVLmqpCLvOq6uJjw7surpBvq85I0r0W5c7qnq75aavqnXiEfMa-eamusH8Sr9cjvCJKu3KhrsVhq-FYWviW2ryVja6lasrbGTKkhg69laOvKW-CupZrhdfANSlvTt15k2mUusAdnSsc40sGfVJPW3BT1naXLkutaVLrGTS6+R0uuEVLrwzS63R0uvz1LrUzb6y9eGv2lGLjtXUrDZq0fW6tb1zi-ddCtyka8wN6s5jcEvY3FjhN0S7je2v0UXS0N0ApDc7PXXjr5N068Tf7NylBzUpYc54RP3a1Qb451m+Va5uG9jSs550uPoutjdTSy5sW81eRvz6Jb8ZkvALelzg3llItyizLeou-XtZQthGzqQP3a3mL7N-y5rfYv4lFboDfW4+Y+vPm5b-Fzm-eNVvrWlaZtwYRbctN23drTt95Q7dktS3uzdJZ27eGBuStAbNui67BdNvwWw7D1hW8hetKoWo7pRp297rjvYXlS-uzm-hZTutXKbxFrOyvozu7mY7atx68CYLvuW07Ot4eUjZLvjXfr6S00pkudI7MG781-2-nuNKkCm7j+j6xQI7vfmy7iVhO-+bzsTFIbjYlu37Z7u9mB7LN026pblLqWpSuRhe9Hd+uFGV7xR-24ZetK07Obplne41bXvS3Hr7Ug+98Y3v52Lrjls+85bnsa3lSAi50p5eNKz8n7tdh+0bY-vwmL7wVu+zjb-u8Wr7kVj69FbfuO3kbgTL64E1hsmjTSZosBz7aXsM2AHill+7aNNszaLrhV60kvOdIra8H-NodqaWN7EPjLlNw+caUNUEPoznN5tsDfau0P7LCt14dQ9vv+2HVOD48xg8rsNdq7zD9+zqX+2sPNTjD2a9w--vsPwr5D4B9I6JtylYdlD-u1g4ptO3EFpD7-aI8QfyPkHkjpm9o-OsDnQDY5m68Y80tPnfThj8q9FvnrRapm0WtwdFp+vBlIzljmh0OdjM5l8h-pfA948Lty4IysZe+8mS4fmOeH6ZPh-4-zOBPJrXpE26E7EfxPLbG5vG9E8NPxlaz7j+s546UeuPB7uT60-k+kvZP0rsTye8k+nuZODHY5tm9U-pNAWe9A53m26R64+kBNQ54W-6VFuNPU74ZSW907cf9P6jgzmEq06Yf+OVbnT4u0ua33xktbszsJ05vPP1OBH0Za85mSM2TOEnM5szZs8AfDOrN7T7uxuef3rOcntT384c8kv7OhVlzrR8050fbOKn1zkIf6VDsDnw7T5yO+89XvBlY7OZeO988TtXnk7-znp9GXTtDnM7oL7O0BdzvQvL7gL7q686mf+PS7kLkJzOfg2Zk0xyLg22OfrvYu4nmLrG-i9bvEvKznzmR7C6OfUvwHe5ivT6Sr2EurnpLjR+i5KeUuyntLwA6y9yvxl57bpRe2OeXuCufn4Zde6K83sznt7OZXe0Of3uyvD7wZZnf6VPuKvz7krhF8K78fKuUXurwiaq4xcbnn7-LiJ-q+rk+kZdmZQK6a62fGuyX9ril9K6pdXnQHhrul0ucgeWuVHrrj2767ZcDnAmwzU9ZlfldPPtXVTt0pg4HPYOcyuD-0vg4TdWOiHmZEh6m7IdAWKH8ZKh0m4Gdjm6HPpBh0Oc6vpvWjT53q6W9lPZujXmbhZ6NdzcWvK33qpt94cLckuo3Dr2t0643PLXq3cjjtx6-8eYMHH8Cttyy4Hf7X83h1mNw857fhuJ3s9-MkY-xLQrZhTZO668VXfDNV3dHVd-PVXdTNV3bg1d04+GDQqtK0KjJtCvI7QrCK0K7d8mfXd6uz3RWhsuXZfdhPhyb7xt32RidLuiX9FOsg+87eO06yN7gm1IS7LfvhLfhYcse8EPqlhy+7mm9B-tOeFhyd78Sb+75foeanK7jm7B4aebumn+ZFp02TafhFhoHTyD10+I9guhyfTuj3m-w-WXaym58j2M6zxUedXZ7-c+WRme4ea3oHxU4J6WfCeVnDHz+7x4A9K1uPdr2Tzs5o9SOFPLrtjzS-E+DuuPDmosh4P49+u1PAbpj3c9I+zuVPejlj5G-zJvPN3HzxD185s9iu2yfz2DwC4c9AvayILlz-R85YQvKPULrzzC9A9wuAvWrld+RabLR7yyaLvz0J48+fucXkH6E4l6k9OeZPQX9t1Z5A9xfu3snzu1F-U-ZeSbyXza5l4ucxfx3pXyd2F+ndufQLlX1B8V5w+weBX+ZIVyu5FetfHPQ5CV516leAeZXzXjN6B4VeDfzL6HlV5B7VejfRT03hTbN6U3lku1RZVy4t9i+dkTX43s12e9HXLeUv3XtL7WVX67eJHiH1aU2WXXneCv63rJ-N8eWbvoHx34e5t8M-teavr3rl8N-ne9emvlH6N5u9jewf43kHxN8D-KvILN8+7tN+WVqtNks36HnN6D+Y-5kC3sP+W3LnB+2FUfZbxDxW+h9BO2yB7PH84cA-1vEfP7sn826J+3n-vGXnH1l87KLWiyvb+H1d-R8KOKflMrH3k5p8Ve6fL35H294F8ffay2Orn4u8nLLvRyJj-ErOXxEoWLHcF2A-L8quO1ZfUzWX24Nl+nvwRLjxX8fZoseOkLXj48qF6l88edfz7i3wa5N8vzlfxPoi9QYQtRPtyaNmCxjZt+4yZy5ZvXzl9V8QenfrPw8jd7IsFsvfPrvC8Ibt9VezfHLiX6Z799fe4-lnycnh9HIEeyLRHmXyR5T-lXawFHuC9R4Qu0es-3nvP0q+GBl+kfOfwL3hfY8oXlx25CZ-OT4-N-8f55OZ0X7CeV-vLJfvF7388P9+RHSFvljOUU+d-fftf1TzRftv1-g-Bfs54P-xPj+nvw-wC6r+Auz-hf0-xPzBeDszlrPMv2zzBfs+H+uvYAWsM57IuufT-7nmi556v+l-fPcF-zw-5r93+0fe5cPfOXC8oXIv3-tv+f60WCFli6-+W3uCJJewAXt6ABB3u-7yeqvvjL7+ynvAFT+S5MXqIBmnhX4Mu25Ey6gBvPsf5r+eFuPbYB8foQE7+RFu2LbkLXpORteo5B17UBZ-ntJ68lASr54WA3mRZyu7AaX7VGM5BN4IWU3pwEautAZx4V+19nwGW+55Ct7zkj9ihYbeSFq-YyBEnuf5WuCgd-Yy+R3swEneMFmd4qBaTmIH9uQgRgHgiXrhoHc+agfp40W8DjoGJGAgXV70B5ngYE-ecFn94y+APmRZA+CFiD4eBufim4oWUPvOQw+vgaX4I+XgVX4wWKPoEGCBk5CW4RBSLv4HiB5-hw4hBjhkkFlaKQSywxBgxqORCOGQa27bkvhnkH0+S5Iz4FBttkhbwMM5Oz5pBd3i4Hh+NFmo4lB0flEGC+TQVv5FBZAar5kMEFO6YPk0vnSSPkcvlIT9BwzP0F0c-QfPT9BUzP0FuC-Qdr4XiuvviSPkGTI+Tkc75F0Gm+V5I+7-kpQn0GvuPQWt5y4d5GsGoyWwYoF3k4we75gUiJhsGFBWeHeQrB-vn4R3kWlHeSPigwaH57BZXq8QvB5wQQEl4LwcMGgEhFC8H3B6Dn0Gp+V5On5fBmfmCFn+p4uVZwhfXkrQIh22o8HF+MIfVZIhjHgsFSaqIax5-BdfoMEN+-5E37PkLfqSEAByIbb6EhYTpSHpB1IX37ohA-oyFD+4RLSGBSt5GP64hE-viEoBtwTP70hRXuSEleEIbUEHBXghyG-BYoc0H0UbIWKoChDXkKGOBCwQf59BR-kiEn+qobCGX+Xwdf6aht-gcH3+Ood55liY3o8Ev+RoW-4GhH-m+Rf+z5D-6DBf-naEUhQAWaE0hCXk6EMhV5AS7-kjdj6G0+MoQgEPk7dg6G8hNoYH5hhhgReJYBfoZ8HKh5gVaH8+XodKHqhJAX8ELMKwRQH-kVATKE0BV5HQE5hsIT155hLAX8FsBXwRwHlhxodwEPkvAY8H8BlYZEEFhpFg2GxBz5Et41hFIdIGDBsgayHyB3YacHKB-YaoF9B6gVmE3Bb5NoFDhugXWHhhUYPqJjhwoU2GmBI4fGG3BlgVOHWBLYaG69h7QWmSKiSoX0HOBh4XU6O0IIhrS3kngY8FraD5D4GDBfgc+QBBd4caHBBV4fr4HB4QU+GNhSIdEGfhrYa+HSmXwYkH-hyQcBGpBoEXSEPhpwdkG-hLIYBH+h34eOFRgxQf+TM+4EfMZoR5MjBGc+KEaKG3B9QThGJhMoejoERtgURG7hfwZ0HkU+VjZa9BJlhu5aWCvgxHlWiFDFqUU1VkrQsRbgixGzBRFPMFRWmBmxGWhWeOhRQUPjvhSbB4kfEHlCokfsHCR2ZkxFieDls76CRTIXREwBHlsmwyRmgRxEpOVEaUFqWGTgZFz+CkWTYmRbtrhR4BOkZKFyRyYTRGphGkeREORyfgZbghLkSeEOW0ISZbZ+bkeob4U+flpaF+yFGiFeR3ngYKmhaljiERReIR5YEhKlkSF+R5vq-hkhQUQAFhRIEVFH2+NlnrYJRnoT5GqReUbBEBR8EVlGIRSUUgEeRoYWhT8hcUcZFRW2nrBS6eOUSv4ZRjQQVFoeKUa0HCRQQg1GghJliqF9R7kQFYahA0aoZaW2oWNElhHlr-ywUhoRNEYhNlk-5zRwMjNHRRwkcF5qWtochT2hKlo6FbRqUS6EbRYTjiDuhe0blEcR3ofhS+hl0cVEOWgYQhTBhO0ZVGv4aAStGRhRFNGHXRsYVFa1iUFPTKvRxniNGkR50Y5FrRvUQZbZhHEbmHgxZjiZbaWsFEWHQxiITZZlhWlhWGoxoUdWEIUtYWpb1h6MV+HIxwgWhSiByFO2FYxqUV2EqWPYS5Z9hlMYoF38+UZDHqRwkaOH4USuvDHlRAVhd5kx+gbDG1RvMYuGMxX0fzHNR1MdZHDA9MZuF4xQMQTH2BwseL4GWR4SZauBLlu4HIUl4WpbXhCFLeEqW94WrFDeDlnD56x4USrFvhwkR+E6x1oWhQ-hFsdj4KxUkUBEaxskeLGv0UFKT42x5Pu7GU++FNNZaxN0QFag6vsdyEeWqEY7E8xdsW9He8hooHHLhSsauHOxYsVbG2RBsfZFmxIMfHHORStMjwZMyPORzI8olGf7I8dHMjzz0yPFMzI8bgsjw8RHFFpQcU2cYb7hE3FIJSExnPBJHCU2weqTk8Tce+6hSYTlJRdxHsTJRQBzPP3G-2dJCJQjx4OlxQPBDcYZGvEfcRPHVBY8Qh7sUkflIRSURcXTYzxKccMBSUucXZTCUrkZnGQh+JM9zQsa8d5FHx5VqfEHCzFIFENxwUexTi21FFiFjxkUXPGy2z8ZbGc88UQfGJRDFMlH3xAAdfGDWklCJ6gJYAd-GKBwCfHS3xTMTvEj+n8dpGO00CaFKIJ04YAlhxl8W9EoJLtufG4R8CXHFCsXtlxQb+eCZ1EEJssY-Fgxmcf1HsUaocgnDRdCQXHjRY8bqEdx00VxSzRrCd56VcRksJTmhJ8T5zMU60XPGbRDcdtGSUu0eIlAJB0aIm9xJ0dIlnRDCUPFXR-CX7Fy4vCdfpqJQcVniaJkOmvEvRnCXzFMJAscolCxJiSLGCJCcZzxEBRieQlCs6YcInUJyCRDEuJg0Ron5hmcXDFcUCMV4mTRuiSjFjxaMUEk8JmMWvHYxc8bjEhJ+MfxQD8zFMTENxpMeElAJFMZJRUxJ8TTFpJUCYOHCUNrrknqJASaVEMUk4fkn6RkSbOGc884ckmmJsSfglCssDtRTrhpSQDHsUgTDxTWi8Sc4n8UisexTKxJ8arENx6sXPGaxa8drGSUusYMn6xJeKBwEkzFC+GTJoQZnHmx4yV-EMU1sSsm2xSyfEEzJGIGXGE+oyb3FuxGyQPELJDMcgk+xByXAHdJRSTMm5xIccMkVJaycYlbJNSdMmju1FPhGXJrUS8ktJPyduEPJlCX8mumHVpL5tWtETVb0RdJGpTDMalHRxqU89GpRTMalG4JqUPEZpRGUpscMBKUS1sb4aUYkXil-xelBinW+BKd3HhS8kVCmO+JlMpEgpUAfJRwpmkT1be+C1rpEWUT0dpSzxLKc8mO01lCinLxBVqvGkp3yTymbxU1oCHEpPLlykZxPKYfEyp7iVnjAsMMTVYXxcqb5EaU-kVCl3xU1g-EFWT8XJQvxbVm-ELWH8fqmrJiqc2HGphKQAnapAAeanpRNqZlGqU2UeqmKBdqV7Eupw4YakFJWKZyFWU1tj1avmpqZgmqpgoSZT1RQaTHHKphCeFLEJHVqQkep0sU6lpxdAG6nApGlLQkFW9CapSMJmaWf7fMnDIpRsJNVhwkdWXCW1Y+KclItFQpAidWmrRWKSIkLWYiVNYSJVlFInNptqbImNpYTvmkeSlaa6kXR6aXAkppzdj1Z3RpaRzEjWeXuOnBp2adymzpryZOl1J4Uj9Gjp1idpS2J06YmkGUjiaunSpqlK4n7p8qVimeJPKd4kdWviaen+Jx6exGXpuqnJQjeVlGEkaUESQtZRJbVrZb3pzcdpQJJU1kknPptqakmPp3aZklAZSiYel-u76UOnhSLMf+lIJ4GXs6-p7KWkzoRoGaGmoZ5piZQPePVg0mfphEQVZBuilG0mEZyadBldJBlD0kFWfSVCkDJU1kMkLWIyRpRjJVlBMm0ZUySNaGxzGeX4ppxqnJTLJnGTEnkZX6Ygz+EPVrj4dWDsaxlkp2lC7GiZECdJmup0EYxlQZ8mVcmCZcGWpkIZ9GUhnlBsmW9HCZUceJlLpKmZYnUZa6fpkwpwHIpSi+vGWRn+UoKfRR605HHrThUjEXSR60dHHrTz0etFMzm0nlI6x+ZXGVFICR7lHWmF0qyR7QBZmyY7Tq0XmbsFBUmZq8QBUkWT35uZNKZ4TBUyWYVGpZ3qWFnqZdmROmhU08Ylmcp2WW9FRUbglFQ+ZgqTFQoePlLH4OZ4qXVmSppWZBZJUAYOxhpU8mBzi2IZKGpi5UZcACjiokAJKjxYxVL1SBA-VAXADAHAKpjFwrmHVT5Uw2YVQBYXKBHCVU0QLsB9ZikBrj1UUAOnC4oxaKEAtUfKILRDZI2UVQ9w42WVTEogOAqjEAfkHIBAAA Open this visualization in the Vega Editor (although the link is long, and may not work with Internet Explorer)>++@+let aggTrans = transform+               . calculateAs \"cos(datum.RA_ICRS * PI / 180)\" \"cosRA\"+               . calculateAs \"sin(datum.RA_ICRS * PI / 180)\" \"sinRA\"+               . aggregate+                   [ opAs Mean \"cosRA\" \"cosRA0\"+                   , opAs Mean \"sinRA\" \"sinRA0\"+                   , opAs Mean \"RA_ICRS\" \"wrong_ra0\"+                   , opAs Mean \"DE_ICRS\" \"dec0\"+                   ]+                   [ \"Cluster\" ]+              . calculateAs \"atan2(datum.sinRA0,datum.cosRA0) * 180.0 / PI\" \"ra0\"++    clusterTrans = aggTrans+                   . aitoffTrans \"datum.ra0\" \"datum.dec0\"++    pos ax field = position ax [ PName field+                               , PmType Quantitative+                               , PScale [SNice (IsNice False)]+                               ]+    enc = encoding+          . pos X \"x\"+          . pos Y \"y\"+          . color [ MName \"Cluster\", MmType Nominal, MLegend [] ]+    encText = enc+              . text [ TName \"Cluster\", TmType Nominal ]++    clusterSpec =+        asSpec [ clusterTrans [], enc [], mark Circle [ MSize 90 ] ]++    clusterLabelSpec =+        asSpec [ clusterTrans [], encText [], mark Text [ MAlign 'AlignLeft'+                                                        , MdX 8 ] ]++    uncorrectedTrans = aggTrans+                       . aitoffTrans \"datum.wrong_ra0\" \"datum.dec0\"++    uncorrectedSpec =+        asSpec [ uncorrectedTrans [], enc [], mark Circle [ MSize 200, MFilled False ] ]++in toVegaLite  [ aitoffConfig []+               , width 570+               , height 285+               , gaiaData+               , layer (clusterSpec : uncorrectedSpec : clusterLabelSpec : graticuleSpec)+               ]+@++-}++clusterCenters :: VegaLite+clusterCenters =+  let aggTrans = transform+                 . calculateAs "cos(datum.RA_ICRS * PI / 180)" "cosRA"+                 . calculateAs "sin(datum.RA_ICRS * PI / 180)" "sinRA"+                 . aggregate+                     [ opAs Mean "cosRA" "cosRA0"+                     , opAs Mean "sinRA" "sinRA0"+                     , opAs Mean "RA_ICRS" "wrong_ra0"+                     , opAs Mean "DE_ICRS" "dec0"+                     ]+                     [ "Cluster" ]+                . calculateAs "atan2(datum.sinRA0,datum.cosRA0) * 180.0 / PI" "ra0"++      clusterTrans = aggTrans+                     . aitoffTrans "datum.ra0" "datum.dec0"++      pos ax field = position ax [ PName field+                                 , PmType Quantitative+                                 , PScale [SNice (IsNice False)]+                                 ]+      enc = encoding+            . pos X "x"+            . pos Y "y"+            . color [ MName "Cluster", MmType Nominal, MLegend [] ]+      encText = enc+                . text [ TName "Cluster", TmType Nominal ]++      clusterSpec =+          asSpec [ clusterTrans [], enc [], mark Circle [ MSize 90 ] ]++      clusterLabelSpec =+          asSpec [ clusterTrans [], encText [], mark Text [ MAlign AlignLeft+                                                      , MdX 8 ] ]++      uncorrectedTrans = aggTrans+                         . aitoffTrans "datum.wrong_ra0" "datum.dec0"++      uncorrectedSpec =+          asSpec [ uncorrectedTrans [], enc [], mark Circle [ MSize 200, MFilled False ] ]++  in toVegaLite  [ aitoffConfig []+                 , width 570+                 , height 285+                 , gaiaData+                 , layer (clusterSpec : uncorrectedSpec : clusterLabelSpec : graticuleSpec)+                 ]++{-++Other things to do:++ - add some description of magnitude / parallax meanings+   (since talk about astronomy being awkward)++ - tooltips (show multiple fields)++ - for errors section, could look at quantile plots?++-}
src/Graphics/Vega/VegaLite.hs view
@@ -1,10334 +1,1582 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TupleSections #-}-{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}--{-|-Module      : Graphics.Vega.VegaLite-Copyright   : (c) Douglas Burke, 2018-2019-License     : BSD3--Maintainer  : dburke.gw@gmail.com-Stability   : unstable-Portability : CPP, OverloadedStrings, TupleSections--This is a port of the-<http://package.elm-lang.org/packages/gicentre/elm-vegalite/latest Elm Vega Lite module>,-written by Jo Wood of the giCentre at the City-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 3__ of the-<https://vega.github.io/schema/vega-lite/v3.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>).--Although this is based on the Elm module, there are differences, such-as using type constructors rather than functions for many properties --such as @PName \"HorsePower\"@ rather than @pName \"HorsePower\"@ --and the return value of 'toVegaLite'. The intention is to keep close-to the Elm module, but it is more a guide than an absolute-requirement!--Please see "Graphics.Vega.Tutorials.VegaLite" for an introduction-to using @hvega@ to create visualizations.--== Example--Note that this module exports several symbols that are exported-by the Prelude, such as 'filter', 'lookup',-and 'repeat'; to avoid name clashes it's therefore advised-to either import the module qualified, for example:--@-import qualified Graphics.Vega.VegaLite as VL-@--or to hide the clashing names explicitly:--@-import Prelude hiding (filter, lookup, repeat)-@--In the following example, we'll assume the latter.--Let's say we have the following plot declaration in a module:--@-\{\-\# language OverloadedStrings \#\-\}--vl1 =-  let desc = "A very exciting bar chart"--      dat = 'dataFromRows' ['Parse' [("start", 'FoDate' "%Y-%m-%d")]]-            . 'dataRow' [("start", 'Str' "2011-03-25"), ("count", 'Number' 23)]-            . 'dataRow' [("start", 'Str' "2011-04-02"), ("count", 'Number' 45)]-            . 'dataRow' [("start", 'Str' "2011-04-12"), ("count", 'Number' 3)]--      barOpts = ['MOpacity' 0.4, 'MColor' "teal"]--      enc = 'encoding'-            . 'position' 'X' ['PName' "start", 'PmType' 'Temporal', 'PAxis' ['AxTitle' "Inception date"]]-            . 'position' 'Y' ['PName' "count", 'PmType' 'Quantitative']--  in 'toVegaLite' ['description' desc, 'background' "white"-                , dat [], 'mark' 'Bar' barOpts, enc []]-@--We can inspect how the encoded JSON looks like in an GHCi session:--@-> 'A.encode' $ '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\/v3.json\",\"encoding\":{\"x\":{\"field\":\"start\",\"type\":\"temporal\",\"axis\":{\"title\":\"Inception date\"}},\"y\":{\"field\":\"count\",\"type\":\"quantitative\"}},\"background\":\"white\",\"description\":\"A very exciting bar chart\"}"-@--The produced JSON can then be processed with vega-lite, which renders the following image:--<<images/example.png>>--which can also be-<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuMxIGMD2Abb8qUALgKay6QA0U2ADrJgJbECeRADAHQAsNkbOqSKQARgkgBfKuCgATWMVhFQECJABuFAK6kAzkQDastekh6l8YiIBMHAIz2AtBwDMTmwFZqUHNoB21mg2rtImahgWCEFQdo4uPC42PljYATE8nmGmEJGWMZBxzhyJ9sn8foFEoeEAujKmkABmBHAxGAzwesJoedEiCmQoAOQApACaTqPQU3LDUpKy2VAAJHqYABakcCIbxMR0eigA9McapADmsFwXLBvaolxM2MfrW3Bnl7BOuCykZ64uAArPTYfzUWSQUj+HByJj+C4qcKQAAeSJyUCaTFIuDkIiiVghGIErCEIjI0DoBAoRJykFgKKYBl6AhYuB6UAAkjDSHRiM9-GBBsJFqZlup2CysTi8WhUukUoIOZAAI7aWCBFiKJjnKRLBpQcSYRAXeBpfyyqAAdw2f1pkDk+kw8CYfIFIgAgmBzvBWGBSCjmPyEWBxPAwJt+gbUv4sYjeotJEA displayed in the Vega Editor>.--Output can be achieved in a Jupyter Lab session with the @vlShow@ function,-provided by @ihaskell-vega@, or 'toHtmlFile' can be used to write out a page of-HTML that includes pointer to JavaScript files which will display a Vega-Lite-specification (there are also functions which provide more control over-the embedding).---}--module Graphics.Vega.VegaLite-       (-         -- * Creating a Vega-Lite Specification--         toVegaLite-       , toVegaLiteSchema-       , vlSchema2, vlSchema3, vlSchema4, vlSchema-       , fromVL-       , VLProperty(..)-       , VLSpec-       , VegaLite-       , PropertySpec-       , LabelledSpec-       , BuildLabelledSpecs-       , Angle-       , Color-       , Opacity-       , ZIndex-       , combineSpecs-       , toHtml-       , toHtmlFile-       , toHtmlWith-       , toHtmlFileWith--         -- * Creating the Data Specification-         ---         -- $dataspec--       , dataFromUrl-       , dataFromColumns-       , dataFromRows-       , dataFromJson-       , dataFromSource-       , dataName-       , datasets-       , dataColumn-       , dataRow-       , noData-       , Data-       , DataColumn-       , DataRow--         -- ** Geographic Data--       , geometry-       , geoFeatureCollection-       , geometryCollection-       , Geometry(..)--       -- ** Data Generators-       ---       -- $datagen--       , dataSequence-       , dataSequenceAs-       , sphere-       , graticule-       , GraticuleProperty(..)--       -- ** Formatting Input Data-       ---       -- $dataformat--       , Format(..)-       , DataType(..)--         -- * Creating the Transform Specification-         ---         -- $transform--       , transform--         -- ** Map Projections-         ---         -- $projections--       , projection-       , ProjectionProperty(..)-       , Projection(..)-       , ClipRect(..)--         -- ** Aggregation-         ---         -- $aggregation--       , aggregate-       , joinAggregate-       , opAs-       , timeUnitAs-       , Operation(..)--         -- ** Binning-         ---         -- $binning--       , binAs-       , BinProperty(..)--         -- ** Stacking-         ---         -- $stacking--       , stack-       , StackProperty(..)-       , StackOffset(..)--         -- ** Data Calculation-         ---         -- $calculate--       , calculateAs--         -- ** Filtering-         ---         -- $filtering--       , filter-       , Filter(..)-       , FilterRange(..)--         -- ** Flattening-         ---         -- $flattening--       , flatten-       , flattenAs-       , fold-       , foldAs--         -- ** Relational Joining (lookup)-         ---         -- $joining--       , lookup-       , lookupAs--         -- ** Data Imputation-         ---         -- $imputation--       , impute-       , ImputeProperty(..)-       , ImMethod(..)--         -- ** Data sampling-         ---         -- $sampling--       , sample--         -- ** Window Transformations-         ---         -- $window--       , window-       , Window(..)-       , WOperation(..)-       , WindowProperty(..)--         -- * Creating the Mark Specification-         ---         -- $markspec--       , mark-       , Mark(..)--         -- ** Mark properties-         ---         -- $markproperties--       , MarkProperty(..)-       , StrokeCap(..)-       , StrokeJoin(..)--         -- *** Used by Mark Properties--       , Orientation(..)-       , MarkInterpolation(..)-       , Symbol(..)-       , PointMarker(..)-       , LineMarker(..)-       , MarkErrorExtent(..)-       , TooltipContent(..)--         -- ** Cursors-         ---         -- $cursors--       , Cursor(..)--         -- * Creating the Encoding Specification-         ---         -- $encoding--       , encoding-       , Measurement(..)--         -- ** Position Channels-         ---         -- $position--       , position-       , Position(..)--         -- *** Position channel properties--       , PositionChannel(..)--         -- ** Sorting properties-         ---         -- $sortprops--       , SortProperty(..)-       , SortField(..)--         -- ** Axis properties-         ---         -- $axisprops--       , AxisProperty(..)--         -- ** Positioning Constants-         ---         -- *** Text Alignment--       , HAlign(..)-       , VAlign(..)--         -- *** Overlapping text--       , OverlapStrategy(..)--         -- *** Legends--       , Side(..)--         -- ** Mark channels-         ---         -- $markprops--       , size-       , color-       , fill-       , stroke-       , strokeWidth-       , opacity-       , fillOpacity-       , strokeOpacity-       , shape--         -- *** Mark Channel properties--       , MarkChannel(..)--         -- *** Mark Legends-         ---         -- $marklegends--       , LegendType(..)-       , LegendProperty(..)-       , LegendOrientation(..)-       , LegendValues(..)--         -- ** Text Channels-         ---         -- $textchannels--       , text-       , tooltip-       , tooltips-       , TextChannel(..)-       , FontWeight(..)--         -- ** Hyperlink Channels-         ---         -- $hyperlink--       , hyperlink-       , HyperlinkChannel(..)--         -- ** Order Channel-         ---         -- $order--       , order-       , OrderChannel(..)--         -- ** Facet Channel-         ---         -- $facet--       , row-       , column--         -- ** Level of detail Channel-         ---         -- $detail--       , detail-       , DetailChannel(..)--         -- ** Scaling-         ---         -- $scaling--       , ScaleProperty(..)-       , Scale(..)-       , categoricalDomainMap-       , domainRangeMap-       , ScaleDomain(..)-       , ScaleRange(..)-       , ScaleNice(..)--         -- *** Color scaling-         ---         -- $color--       , CInterpolate(..)--         -- * Creating view compositions-         ---         -- $view--       , layer-       , vlConcat-       , columns-       , hConcat-       , vConcat-       , align-       , alignRC-       , spacing-       , spacingRC-       , center-       , centerRC-       , bounds-       , Bounds(..)-       , CompositionAlignment(..)--         -- ** Resolution-         ---         -- $resolution--       , resolve-       , resolution-       , Resolve(..)-       , Channel(..)-       , Resolution(..)--         -- ** Faceted views-         ---         -- $facetview--       , repeat-       , repeatFlow-       , RepeatFields(..)-       , facet-       , facetFlow-       , FacetMapping(..)-       , FacetChannel(..)-       , asSpec-       , specification-       , Arrangement(..)--         -- *** Facet Headers-         ---         -- $facetheaders--       , HeaderProperty(..)--         -- * Creating Selections for Interaction-         ---         -- $selections--       , selection-       , select-       , Selection(..)-       , SelectionProperty(..)-       , Binding(..)-       , InputProperty(..)-       , SelectionMarkProperty(..)--       -- ** Selection Resolution-       ---       -- $selectionresolution--       , SelectionResolution(..)--         -- ** Making conditional channel encodings-         ---         -- $conditional--       , BooleanOp(..)--         -- ** Top-level Settings-         ---         -- $toplevel--       , name-       , description-       , height-       , width-       , padding-       , autosize-       , background-       , usermetadata-       , Padding(..)-       , Autosize(..)--         -- *** Title-         ---         -- $title--       , title--         -- *** View Backgroud-         ---         -- $viewbackground--       , viewBackground-       , ViewBackground(..)--         -- ** Style Setting--       , configure-       , configuration-       , ConfigurationProperty(..)--         -- ** Axis Configuration Options-         ---         -- $axisconfig--       , AxisConfig(..)--         -- ** Legend Configuration Options-         ----       , LegendConfig(..)-       , LegendLayout(..)-       , BaseLegendLayout(..)--         -- ** Scale Configuration Options-         ---         -- $scaleconfig--       , ScaleConfig(..)--         -- ** Scale Range Configuration Options-         ---         -- $scalerangeconfig--       , RangeConfig(..)--         -- ** Title Configuration Options-         ---         -- $titleconfig--       , TitleConfig(..)-       , TitleFrame(..)--         -- ** View Configuration Options-         ---         -- $viewconfig--       , ViewConfig(..)-       , APosition(..)-       , FieldTitleProperty(..)--         -- ** Facet Configuration Options-         ---         -- $facetconfig--       , FacetConfig(..)--         -- ** Concatenated View Configuration Options-         ---         -- $concatconfig--       , ConcatConfig(..)--         -- * General Data types-         ---         -- $generaldatatypes--       , DataValue(..)-       , DataValues(..)--         -- ** Temporal data-         ---         -- $temporaldata--       , DateTime(..)-       , MonthName(..)-       , DayName(..)-       , TimeUnit(..)--         -- * Update notes-         ---         -- $update--         -- ** Version 0.4-         ---         -- $update0400--        )-    where---- VegaLite uses these symbols.-import Prelude hiding (filter, lookup, repeat)--import qualified Data.Aeson as A-import qualified Data.Aeson.Text as A-import qualified Data.HashMap.Strict as HM-import qualified Data.Text as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.IO as TL-import qualified Data.Vector as V--import Control.Arrow (first, second)---- Aeson's Value type conflicts with the Number type-import Data.Aeson (Value, decode, encode, object, toJSON, (.=))-import Data.Maybe (catMaybes, fromMaybe, mapMaybe)--#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)----- Documentation---- $dataspec--- Functions and types for declaring the input data to the--- visualization. See the--- [Vega-Lite documentation](https://vega.github.io/vega-lite/docs/data.html#format).---- $datagen--- Functions that create new data sources.---- $dataformat--- See the Vega-Lite--- [format](https://vega.github.io/vega-lite/docs/data.html#format) and--- [JSON](https://vega.github.io/vega-lite/docs/data.html#json) documentation.---- $transform--- Functions and types for declaring the transformation rules that--- are applied to data fields or geospatial coordinates before they--- are encoded visually.---- $projections--- See the--- [Vega-Lite map projection documentation](https://vega.github.io/vega-lite/docs/projection.html).---- $aggregation--- See the--- [Vega-Lite aggregate documentation](https://vega.github.io/vega-lite/docs/aggregate.html).---- $binning--- See the--- [Vega-Lite binning documentation](https://vega.github.io/vega-lite/docs/bin.html).---- $stacking--- See the [Vega-Lite stack documentation](https://vega.github.io/vega-lite/docs/stack.html).---- $calculate--- See the--- [Vega-Lite calculate documentation](https://vega.github.io/vega-lite/docs/calculate.html).---- $filtering--- See the--- [Vega-Lite filter documentation](https://vega.github.io/vega-lite/docs/filter.html).---- $flattening--- See the Vega-Lite [flatten](https://vega.github.io/vega-lite/docs/flatten.html)--- and [fold](https://vega.github.io/vega-lite/docs/fold.html)--- documentation.---- $joining--- See the--- [Vega-Lite lookup documentation](https://vega.github.io/vega-lite/docs/lookup.html).---- $imputation--- Impute missing data. See the--- [Vega-Lite impute documentation](https://vega.github.io/vega-lite/docs/impute.html#transform).---- $sampling--- See the [Vega-Lite sample documentation](https://vega.github.io/vega-lite/docs/sample.html)---- $window--- See the Vega-Lite--- [window transform field](https://vega.github.io/vega-lite/docs/window.html#field-def)--- and--- [window transform](https://vega.github.io/vega-lite/docs/window.html#window-transform-definition)--- documentation.---- $markspec--- Types and functions for declaring the type of visual--- marks used in the visualization.---- $markproperties--- See the Vega-Lite--- [general mark](https://vega.github.io/vega-lite/docs/mark.html#general-mark-properties),--- [area mark](https://vega.github.io/vega-lite/docs/area.html#properties),--- [bar mark](https://vega.github.io/vega-lite/docs/bar.html#properties),--- [boxplot](https://vega.github.io/vega-lite/docs/boxplot.html#properties),--- [circle mark](https://vega.github.io/vega-lite/docs/circle.html#properties),--- [error band](https://vega.github.io/vega-lite/docs/errorband.html#properties),--- [error bar](https://vega.github.io/vega-lite/docs/errorbar.html#properties),--- [hyperlink mark](https://vega.github.io/vega-lite/docs/mark.html#hyperlink),--- [line mark](https://vega.github.io/vega-lite/docs/line.html#properties),--- [point mark](https://vega.github.io/vega-lite/docs/point.html#properties),--- [square mark](https://vega.github.io/vega-lite/docs/square.html#properties),--- [text mark](https://vega.github.io/vega-lite/docs/text.html#properties) and--- [tick mark](https://vega.github.io/vega-lite/docs/tick.html#properties)--- property documentation.---- $cursors--- See the--- [CSS cursor documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#Keyword%20values)---- $encoding--- Types and functions for declaring which data fields are mapped to which--- channels. Channels can include: position on screen (e.g. 'X', 'Y'); visual--- mark properties ('color', 'size', 'stroke', 'shape'); 'text'; 'hyperlink';--- ordering ('order'); level of 'detail'; and facets for composed--- visualizations ('facet'). All can be further customised via a series of--- properties that determine how the encoding is implemented (such as--- scaling, sorting, and spacing).---- $position--- Control where items appear in the visualization. See the--- [Vega-Lite position documentation](https://vega.github.io/vega-lite/docs/encoding.html#position).---- $sortprops--- See the--- [Vega-Lite sort documentation](https://vega.github.io/vega-lite/docs/sort.html).---- $axisprops--- See the--- Vega-Lite axis property documentation](https://vega.github.io/vega-lite/docs/axis.html#axis-properties).---- $markprops--- Control the appearance of the visual marks in the visualization--- (e.g. 'color' and 'size').---- $marklegends--- See the--- [Vega-Lite legend property documentation](https://vega.github.io/vega-lite/docs/legend.html#legend-properties).---- $textchannels--- Control the appearance of the text and tooltip elements in the visualization.---- $hyperlink--- Channels which offer a clickable URL destination. Unlike most other--- channels, the hyperlink channel has no direct visual expression other than the--- option of changing the cursor style when hovering, so an encoding will usually--- pair hyperlinks with other visual channels such as marks or texts.---- $order--- Channels that relate to the order of data fields such as for sorting stacking order--- or order of data points in a connected scatterplot. See the--- <https://vega.github.io/vega-lite/docs/encoding.html#order Vega-Lite documentation>--- for further details.---- $facet--- Channels for faceting single plots into small multiples. Can be used to create--- trellis plots or other arrangements in rows and columns. See the--- <https://vega.github.io/vega-lite/docs/encoding.html#facet Vega-Lite documentation>--- for further details. See also, <#facetview faceted views> for a more flexible (but--- more verbose) way of defining faceted views.---- $detail--- Used for grouping data but without changing the visual appearance of a mark. When,--- for example, a field is encoded by color, all data items with the same value for--- that field are given the same color. When a detail channel encodes a field, all--- data items with the same value are placed in the same group. This allows, for example--- a line chart with multiple lines to be created – one for each group. See the--- <https://vega.github.io/vega-lite/docs/encoding.html#detail Vega-Lite documentation>--- for more information.---- $scaling--- Used to specify how the encoding of a data field should be applied. See the--- [Vega-Lite scale documentation](https://vega.github.io/vega-lite/docs/scale.html).---- $color--- For color interpolation types, see the--- [Vega-Lite continuous scale documentation](https://vega.github.io/vega-lite/docs/scale.html#continuous).---- $view--- Views can be combined to create more complex multiview displays. This may involve--- layering views on top of each other (superposition) or laying them out in adjacent--- spaces (juxtaposition using 'repeat', 'repeatFlow', 'facet', 'facetFlow',--- 'vlConcat', 'hConcat', or 'vConcat'). Where different views have potentially conflicting--- channels (for example, two position scales in a layered visualization) the rules for--- resolving them can be defined with 'resolve'. For details of creating composite views see the--- <https://vega.github.io/vega-lite/docs/composition.html Vega-Lite documentation>.---- $resolution--- Control the independence between composed views.------ See the [Vega-Lite resolve documentation](https://vega.github.io/vega-lite/docs/resolve.html).---- $facetview--- #facetview#--- These are small multiples each of which show subsets of the same dataset. The specification--- determines which field should be used to determine subsets along with their spatial--- arrangement (in rows or columns). For details see the--- <https://vega.github.io/vega-lite/docs/facet.html Vega-Lite documentation>.---- $facetheaders--- See the--- [Vega-Lite header documentation](https://vega.github.io/vega-lite/docs/header.html).---- $selections--- Selections are the way in which interactions (such as clicking or dragging) can be--- responded to in a visualization. They transform interactions into data queries.--- For details, see the--- <https://vega.github.io/vega-lite/docs/selection.html Vega-Lite documentation>.---- $selectionresolution--- Determines how selections are made across multiple views.--- See the [Vega-lite resolve selection documentation](https://vega.github.io/vega-lite/docs/selection.html#resolve).---- $conditional--- To make channel encoding conditional on the result of some interaction, use--- 'MSelectionCondition', 'TSelectionCondition', or 'HSelectionCondition'. Similarly--- 'MDataCondition', 'TDataCondition', or 'HDataCondition' will encode a mark--- conditionally depending on some data properties such as whether a datum is null--- or an outlier.------ For interaction, once a selection has been defined and named, supplying a set of--- encodings allow mark encodings to become dependent on that selection.--- 'MSelectionCondition' is followed firstly a (Boolean) selection and then an--- encoding if that selection is true and another encoding to be applied if it is false.--- The color specification below states \"whenever data marks are selected with an--- interval mouse drag, encode the cylinder field with an ordinal color scheme,--- otherwise make them grey\":------ @--- sel = 'selection' . 'select' "myBrush" 'Interval' []------ enc = 'encoding'---         . 'position' 'X' [ 'PName' \"Horsepower\", 'PmType' 'Quantitative' ]---         . 'position' 'Y' [ 'PName' \"Miles_per_Gallon\", 'PmType' Quantitative ]---         . 'color'---             [ 'MSelectionCondition' ('SelectionName' "myBrush")---                 [ 'MName' \"Cylinders\", 'MmType' 'Ordinal' ]---                 [ 'MString' "grey" ]---             ]--- @------ In a similar way, 'MDataCondition' will encode a mark depending on whether any--- predicate tests are satisfied. Unlike selections, multiple conditions and associated--- encodings can be specified. Each test condition is evaluated in order and only on--- failure of the test does encoding proceed to the next test. If no tests are true,--- the encoding in the final parameter is applied in a similar way to @case of@--- expressions:------ @--- enc = 'encoding'---         . 'position' X [ 'PName' \"value\", 'PmType' 'Quantitative' ]---           . 'color'---               [ 'MDataCondition'---                    [ ( 'Expr' "datum.value < 40", [ 'MString' "blue" ] )---                    , ( 'Expr' "datum.value < 50", [ 'MString' "red" ] )---                    , ( 'Expr' "datum.value < 60", [ 'MString' "yellow" ] )---                    ]---                    [ 'MString' "black" ]---               ]--- @------ For more details, see the--- <https://vega.github.io/vega-lite/docs/condition.html Vega-Lite documentation>.---- $toplevel--- These are in addition to the data and transform options described above,--- and are described in the--- [Vega-Lite top-level spec documentation](https://vega.github.io/vega-lite/docs/spec.html#top-level-specifications).---- $title--- Per-title settings. Use 'TitleStyle' to change the appearance of all--- titles in a multi-view specification.---- $viewbackground--- The background of a single view in a view composition can be styled independently--- of other views. For more details see the--- [Vega-Lite view background documentation](https://vega.github.io/vega-lite/docs/spec.html#view-background).---- $axisconfig--- See the--- [Vega-Lite axis config documentation](https://vega.github.io/vega-lite/docs/axis.html#general-config).---- $scaleconfig--- See the--- [Vega-Lite scale configuration documentation](https://vega.github.io/vega-lite/docs/scale.html#scale-config).---- $scalerangeconfig--- See the--- [Vega-Lite scheme configuration documentation](https://vega.github.io/vega/docs/schemes/#scheme-properties).---- $titleconfig--- Unlike 'title', these options apply to __all__ titles if multiple views--- are created. See the--- [Vega-Lite title configuration documentation](https://vega.github.io/vega-lite/docs/title.html#config).---- $viewconfig--- See the--- [Vega-Lite view configuration documentation](https://vega.github.io/vega-lite/docs/spec.html#config).---- $facetconfig--- See the--- [Vega-Lite facet configuration documentation](https://vega.github.io/vega-lite/docs/facet.html#facet-configuration).---- $concatconfig--- See the--- [Vega-Lite concat configuration documentation](https://vega.github.io/vega-lite/docs/concat.html#concat-configuration).---- $generaldatatypes--- In addition to more general data types like integers and string, the following types--- can carry data used in specifications.---- $temporaldata--- See the--- [Vega-Lite dateTime documentation](https://vega.github.io/vega-lite/docs/types.html#datetime)--- and the [Vega-Lite time unit documentation](https://vega.github.io/vega-lite/docs/timeunit.html).---- $update--- The following section describes how to update code that used--- an older version of @hvega@.---- $update0400--- The @0.4.0.0@ release added a large number of functions, types, and--- constructors, including:------ 'toVegaLiteSchema' has been added to allow you to specify a--- different Vega-Lite schema. 'toVegaLite' uses version 3 but--- version 4 is being worked on as I type this. The 'vlSchema'--- function has been added, along with 'vlSchema4', 'vlSchema3',--- and 'vlSchema2' values. The 'toHtmlWith' and 'toHtmlFileWith'--- functions have been added to support more control over the--- embedding of the Vega-Lite visualizations, and the versions of--- the required Javascript libraries used by the @toHtmlXXX@ routines--- has been updated.------ The 'VLProperty' type now exports its constructors, to support users--- who may need to tweak or augment the JSON Vega-Lite specification--- created by @hvega@: see [issue--- 17](https://github.com/DougBurke/hvega/issues/17). It has also gained--- several new constructors and associated functions, which are given in--- brackets after the constructor: 'VLAlign' ('align'); 'VLBounds'--- ('bounds'); 'VLCenter' ('center', 'centerRC'); 'VLColumns'--- ('columns'); 'VLConcat' ('vlConcat'); 'VLSpacing' ('alignRC',--- 'spacing', 'spacingRC'); 'VLUserMetadata' ('usermetadata'); and--- 'VLViewBackground' ('viewBackground'). It is expected that you will be--- using the functions rather the constructors!--- --- Four new type aliases have been added: 'Angle', 'Color', 'Opacity',--- and 'ZIndex'. These do not provide any new functionality but do--- document intent.--- --- The 'noData' function has been added to let compositions define the--- source of the data (whether it is from the parent or not), and data--- sources can be named with 'dataName'. Data can be created with--- 'dataSequence', 'dataSequenceAs', and 'sphere'. Graticules can be--- created with 'graticule'.  The 'NullValue' type has been added to--- 'DataValue' to support data sources that are missing elements, but for--- more-complex cases it is suggested that you create your data as an--- Aeson Value and then use 'dataFromJson'. Support for data imputation--- (creating new values based on existing data) has been added, as--- discussed below.--- --- The alignment, size, and composition of plots can be defined and--- changed with 'align', 'alignRC', 'bounds', 'center', 'centerRC',--- 'columns', 'spacing', and 'spacingRC'.--- --- Plots can be combined and arranged with: 'facet', 'facetFlow',--- 'repeat', 'repeatFlow', and 'vlConcat'--- --- New functions for use in a 'transform': 'flatten', 'flattenAs',--- 'fold', 'foldAs', 'impute', and 'stack'.--- --- New functions for use with 'encoding': 'fillOpacity', 'strokeOpacity',--- 'strokeWidth',--- --- The ability to arrange specifications has added the "flow" option--- (aka "repeat"). This is seen in the addition of the 'Flow' constructor--- to the 'Arrangement' type - which is used with 'ByRepeatOp',--- 'HRepeat', 'MRepeat', 'ORepeat', 'PRepeat', and 'TRepeat'.--- --- The 'Mark' type has gained 'Boxplot', 'ErrorBar', 'ErrorBand', and--- 'Trail' constructors. The 'MarkProperty' type has gained 'MBorders',--- 'MBox', 'MExtent', 'MHeight', 'MHRef', 'MLine', 'MMedian', 'MOrder',--- 'MOutliers', 'MNoOutliers', 'MPoint', 'MRule', 'MStrokeCap', 'MStrokeJoin',--- 'MStrokeMiterLimit', 'MTicks', 'MTooltip', 'MWidth', 'MX', 'MX2',--- 'MXOffset', 'MX2Offset', 'MY', 'MY2', 'MYOffset', and 'MY2Offset'--- constructors.--- --- The 'Position' type has added 'XError', 'XError2', 'YError', and--- 'YError2' constructors.--- --- The 'MarkErrorExtent' type was added.--- --- The 'BooleanOp' type has gained the 'FilterOp' and 'FilterOpTrans'--- constructors which lets you use 'Filter' expressions as part of a--- boolean operation. The 'Filter' type has also gained expresiveness,--- with the 'FLessThan', 'FLessThanEq', 'FGreaterThan', 'FGreaterThanEq',--- and 'FValid'.--- --- The 'Format' type has gained the 'DSV' constructor, which allow you--- to specify the separator character for column data.--- --- The MarkChannel type has been expanded to include: 'MBinned', 'MSort',--- 'MTitle', and 'MNoTitle'. The PositionChannel type has added--- 'PHeight', 'PWidth', 'PNumber', 'PBinned', 'PImpute', 'PTitle', and--- 'PNoTitle' constructors.--- --- The LineMarker and PointMarker types have been added for use with--- 'MLine' and 'MPoint' respectively (both from 'MarkProperty').--- --- The ability to define the binning property with --- 'binAs', 'DBin', 'FBin', 'HBin', 'MBin', 'OBin', 'PBin', and 'TBin' has--- been expanded by adding the 'AlreadyBinned' and 'BinAnchor'--- constructors to 'BinProperty', as well as changing the 'Divide'--- constructor (as described below).--- --- The 'StrokeCap' and 'StrokeJoin' types has been added. These are used--- with 'MStrokeCap', 'VBStrokeCap', and 'ViewStrokeCap' and--- 'MStrokeJoin', 'VBStrokeJoin', and 'ViewStrokeJoin' respectively.--- --- The 'StackProperty' constructor has been added with the 'StOffset'--- and 'StSort' constructors. As discussed below this is a breaking change--- since the old StackProperty type has been renamed to 'StackOffset'.--- --- The 'ScaleProperty' type has seen significant enhancement, by adding--- the constructors: 'SAlign', 'SBase', 'SBins', 'SConstant' and--- 'SExponent'.  THe 'Scale' tye has added 'ScSymLog' 'ScQuantile',--- 'ScQuantize', and 'ScThreshold'.--- --- The 'SortProperty' type has new constructors: 'CustomSort',--- 'ByRepeatOp', 'ByFieldOp', and 'ByChannel'. See the breaking-changes--- section below for the constructors that were removed.--- --- The 'AxisProperty' type has seen significant additions, including:--- 'AxBandPosition', 'AxDomainColor', 'AxDomainDash',--- 'AxDomainDashOffset', 'AxDomainOpacity', 'AxDomainWidth',--- 'AxFormatAsNum', 'AxFormatAsTemporal', 'AxGridColor', 'AxGridDash',--- 'AxGridDashOffset', 'AxGridOpacity', 'AxGridWidth', 'AxLabelAlign',--- 'AxLabelBaseline', 'AxLabelNoBound', 'AxLabelBound', 'AxLabelBoundValue',--- 'AxLabelColor', 'AxLabelNoFlush', 'AxLabelFlush', 'AxLabelFlushValue',--- 'AxLabelFlushOffset', 'AxLabelFont', 'AxLabelFontSize',--- 'AxLabelFontStyle', 'AxLabelFontWeight', 'AxLabelLimit',--- 'AxLabelOpacity', 'AxLabelSeparation', 'AxTickColor', 'AxTickDash',--- 'AxTickDashOffset', 'AxTickExtra', 'AxTickMinStep', 'AxTickOffset',--- 'AxTickOpacity', 'AxTickRound', 'AxTickWidth', 'AxNoTitle',--- 'AxTitleAnchor', 'AxTitleBaseline', 'AxTitleColor', 'AxTitleFont',--- 'AxTitleFontSize', 'AxTitleFontStyle', 'AxTitleFontWeight',--- 'AxTitleLimit', 'AxTitleOpacity', 'AxTitleX', and 'AxTitleY'.--- --- The 'AxisConfig' has seen a similar enhancement, and looks similar--- to the above apart from the constructors do not start with @Ax@.--- --- The 'LegendConfig' type has been significantly expanded and, as--- discussed in the Breaking Changes section, changed. It has gained:--- 'LeClipHeight', 'LeColumnPadding', 'LeColumns', 'LeGradientDirection',--- 'LeGradientHorizontalMaxLength', 'LeGradientHorizontalMinLength',--- 'LeGradientLength', 'LeGradientOpacity', 'LeGradientThickness',--- 'LeGradientVerticalMaxLength', 'LeGradientVerticalMinLength',--- 'LeGridAlign', 'LeLabelFontStyle', 'LeLabelFontWeight',--- 'LeLabelOpacity', 'LeLabelOverlap', 'LeLabelPadding',--- 'LeLabelSeparation', 'LeLayout', 'LeLeX', 'LeLeY', 'LeRowPadding',--- 'LeSymbolBaseFillColor', 'LeSymbolBaseStrokeColor', 'LeSymbolDash',--- 'LeSymbolDashOffset', 'LeSymbolDirection', 'LeSymbolFillColor',--- 'LeSymbolOffset', 'LeSymbolOpacity', 'LeSymbolStrokeColor', 'LeTitle',--- 'LeNoTitle', 'LeTitleAnchor', 'LeTitleFontStyle', 'LeTitleOpacity',--- and 'LeTitleOrient'.--- --- The 'LegendOrientation' type has gained 'LOTop' and 'LOBottom'.--- --- The 'LegendLayout' and 'BaseLegendLayout' types are new, and used--- with 'LeLayout' to define the legent orient group.--- --- The 'LegendProperty' type gained: 'LClipHeight', 'LColumnPadding',--- 'LColumns', 'LCornerRadius', 'LDirection', 'LFillColor',--- 'LFormatAsNum', 'LFormatAsTemporal', 'LGradientLength',--- 'LGradientOpacity', 'LGradientStrokeColor', 'LGradientStrokeWidth',--- 'LGradientThickness', 'LGridAlign', 'LLabelAlign', 'LLabelBaseline',--- 'LLabelColor', 'LLabelFont', 'LLabelFontSize', 'LLabelFontStyle',--- 'LLabelFontWeight', 'LLabelLimit', 'LLabelOffset', 'LLabelOpacity',--- 'LLabelOverlap', 'LLabelPadding', 'LLabelSeparation', 'LRowPadding',--- 'LStrokeColor', 'LSymbolDash', 'LSymbolDashOffset',--- 'LSymbolFillColor', 'LSymbolOffset', 'LSymbolOpacity', 'LSymbolSize',--- 'LSymbolStrokeColor', 'LSymbolStrokeWidth', 'LSymbolType',--- 'LTickMinStep', 'LNoTitle', 'LTitleAlign', 'LTitleAnchor',--- 'LTitleBaseline', 'LTitleColor', 'LTitleFont', 'LTitleFontSize',--- 'LTitleFontStyle', 'LTitleFontWeight', 'LTitleLimit', 'LTitleOpacity',--- 'LTitleOrient', 'LTitlePadding', 'LeX', and 'LeY'.--- --- 'Projection' has gained the 'Identity' constructor. The--- 'ProjectionProperty' type has gained 'PrScale', 'PrTranslate',--- 'PrReflectX', and 'PrReflectY'. The 'GraticuleProperty' type was--- added to configure the appearance of graticules created with--- 'graticule'.--- --- The 'CompositionAlignment' type was added and is used with 'align',--- 'alignRC', 'LeGridAlign', and 'LGridAlign'.--- --- The 'Bounds' type was added for use with 'bounds'.--- --- The 'ImputeProperty' and 'ImMethod' types were added for use with--- 'impute' and 'PImpute'.--- --- The 'ScaleConfig' type has gained 'SCBarBandPaddingInner',--- 'SCBarBandPaddingOuter', 'SCRectBandPaddingInner', and--- 'SCRectBandPaddingOuter'.--- --- The 'SelectionProperty' type has gained 'Clear', 'SInit', and--- 'SInitInterval'.--- --- The Channel type has gained: 'ChLongitude', 'ChLongitude2',--- 'ChLatitude', 'ChLatitude2', 'ChFill', 'ChFillOpacity', 'ChHref',--- 'ChKey', 'ChStroke', 'ChStrokeOpacity'.  'ChStrokeWidth', 'ChText',--- and 'ChTooltip'.--- --- The 'TitleConfig' type has gained: 'TFontStyle', 'TFrame', 'TStyle',--- and 'TZIndex'.--- --- The 'TitleFrame' type is new and used with 'TFrame' from 'TitleConfig'.--- --- The 'ViewBackground' type is new and used with 'viewBackground'.--- --- The 'ViewConfig' type has gained 'ViewCornerRadius', 'ViewOpacity',--- 'ViewStrokeCap', 'ViewStrokeJoin', and 'ViewStrokeMiterLimit'.--- --- The 'ConfigurationProperty' type, used with 'configuration', has--- gained 'ConcatStyle', 'FacetStyle', 'GeoshapeStyle', 'HeaderStyle',--- 'NamedStyles', and 'TrailStyle' constructors.--- --- The 'ConcatConfig' type was added for use with the 'ConcatStyle',--- and the 'FacetConfig' type for the 'FacetStyle'--- configuration settings.--- --- The 'HeaderProperty' type has gained: 'HFormatAsNum',--- 'HFormatAsTemporal', 'HNoTitle', 'HLabelAlign', 'HLabelAnchor',--- 'HLabelAngle', 'HLabelColor', 'HLabelFont', 'HLabelFontSize',--- 'HLabelLimit', 'HLabelOrient', 'HLabelPadding', 'HTitleAlign',--- 'HTitleAnchor', 'HTitleAngle', 'HTitleBaseline', 'HTitleColor',--- 'HTitleFont', 'HTitleFontSize', 'HTitleFontWeight', 'HTitleLimit',--- 'HTitleOrient', and 'HTitlePadding'.--- --- The 'HyperlinkChannel' type has gained 'HBinned'.--- --- The 'FacetChannel' type has gained 'FSort', 'FTitle', and 'FNoTitle'.--- --- The 'TextChannel' type has gained 'TBinned', 'TFormatAsNum',--- 'TFormatAsTemporal', 'TTitle', and 'TNoTitle'.--- --- The 'TooltipContent' type was added, for use with 'MTooltip'.------ The 'Symbol' type has gained: 'SymArrow', 'SymStroke',--- 'SymTriangle', 'SymTriangleLeft', 'SymTriangleRight', and--- 'SymWedge'.------ There are a number of __breaking changes__ in this release (some--- of which were mentioned above):------ * The 'title' function now takes a second argument, a list of 'TitleConfig'---   values for configuring the appearance of the title.------ * The @SReverse@ constructor was removed from 'ScaleProperty' as it---   represented a Vega, rather than Vega-Lite, property. The @xSort@---   constructors are used to change the order of an item (e.g.---   'PSort', 'MSort').------ * The @ScSequential@ constructor was removed from 'Scale' as---   'ScLinear' should be used.------ * The 'SortProperty' type has had a number of changes: the @Op@,---   @ByField@, and @ByRepeat@ constructors have been removed, and---   'ByRepeatOp', 'ByFieldOp', and 'ByChannel' constructors have been---   added.------ * The @AxTitleMaxLength@ and @TitleMaxLength@ constructors have been---   removed (from 'AxisProperty' and 'AxisConfig' respectively) as they---   are invalid. The 'AxTitleLimit' (new in this release) and---   'TitleLimit' constructors should be used instead.------ * 'AxisProperty': the 'AxValues' constructor has been changed from---   accepting a list of doubles to 'DataValues'. The 'AxDates'---   constructor has been deprecated and 'AxValues' should be used---   instead.------ * There have been significant changes to the 'LegendConfig' type: the---   @EntryPadding@, @GradientHeight@, @GradientLabelBaseline@,---   @GradientWidth@, and @SymbolColor@ constructors have been removed;---   the renaming constructors have been renamed so they all begin with---   @Le@ (e.g. @Orient@ is now 'LeOrient', and 'Orient' has been added---   to 'AxisConfig'); and new constructors have been added.------ * The @StackProperty@ type has been renamed to 'StackOffset' and its---   constructors have changed, and a new 'StackProperty'---   type has been added (that references the 'StackOffset' type).------ * The @Average@ constructor of 'Operation' was removed, and 'Mean'---   should be used instead.------ * The @LEntryPadding@ constructor of 'LegendProperty' was removed.------ * The arguments to the 'MDataCondition', 'TDataCondition', and---   'HDataCondition' constructors - of 'MarkChannel', 'TextChannel',---   and 'HyperlinkChannel' respectively - have changed to support---   accepting multiple expressions.------ * The @MarkOrientation@ type has been renamed 'Orientation'.------ * The constructors of the 'ViewConfig' type have been renamed so they---   all begin with @View@ (to match 'ViewWidth' and 'ViewHeight').------ * The constructors of the 'ProjectionProperty' type have been renamed---   so that they begin with @Pr@ rather than @P@ (to avoid conflicts---   with the 'PositionChannel' type).------ * The 'Divide' constructor of 'BinProperty' now takes a list of---   Doubles rather than two.------ * The 'TitleConfig' type has gained the following constructors:---   'TFontStyle', 'TFrame', 'TStyle', and 'TZIndex'. The 'TitleFrame'---   type was added for use with 'TFrame'.------ * The 'ArgMax' and 'ArgMin' constructors of 'Operation' now take an---   optional field name, to allow them to be used as part of an encoding---   aggregation (e.g. with 'PAggregate').------ * The \"z index" value has changed from an 'Int' to the 'ZIndex' type.------ * The constructors for the 'Symbol' type now all start with @Sym@, so---   @Cross@, @Diamond@, @TriangleUp@, @TriangleDown@, and @Path@ have---   been renamed to 'SymCross', 'SymDiamond', 'SymTriangleUp',---   'SymTriangleDown', and 'SymPath', respectively.------ * The `Legend` type has been renamed `LegendType` and its constructors---   have been renamed 'GradientLegend' and 'SymbolLegend'.----- helpers---- This could be extended to any Ord type but specialize for now to Double-clamped ::-  Double-  -- ^ minimum value allowed-  -> Double-  -- ^ maximum value allowed (must be > the minimum value)-  -> Double-  -- ^ user value-  -> Double-clamped xmin xmax x = max xmin (min xmax x)---aggregate_ :: Operation -> LabelledSpec-aggregate_ op = "aggregate" .= operationSpec op--type_ :: T.Text -> LabelledSpec-type_ t = "type" .= t--field_ :: T.Text -> LabelledSpec-field_ f = "field" .= f---- could restrict to ascending/descending-order_ :: T.Text -> LabelledSpec-order_ o = "order" .= o--op_ :: Operation -> LabelledSpec-op_ op = "op" .= operationSpec op--repeat_ :: Arrangement -> LabelledSpec-repeat_ arr = "repeat" .= arrangementLabel arr--sort_ :: [SortProperty] -> LabelledSpec-sort_ ops = "sort" .= sortPropertySpec ops--header_ :: [HeaderProperty] -> LabelledSpec-header_ hps = "header" .= object (map headerProperty hps)--impute_ :: [ImputeProperty] -> LabelledSpec-impute_ ips = "impute" .= object (map imputeProperty ips)---- TODO: should this turn an empty list into true?-mprops_ :: T.Text -> [MarkProperty] -> LabelledSpec-mprops_ f mps = f .= object (map markProperty mps)--mchan_ :: T.Text -> [MarkChannel] -> LabelledSpec-mchan_ f ms = f .= object (concatMap markChannelProperty ms)--timeUnit_ :: TimeUnit -> LabelledSpec-timeUnit_ tu = "timeUnit" .= timeUnitLabel tu--mtype_ :: Measurement -> LabelledSpec-mtype_ m = "type" .= measurementLabel m---- The assumption at the moment is that it's always correct to--- replace the empty list by null.----scaleProp_ :: [ScaleProperty] -> LabelledSpec-scaleProp_ [] = "scale" .= A.Null-scaleProp_ sps = "scale" .= object (map scaleProperty sps)--scaleConfig_ :: [ScaleConfig] -> LabelledSpec--- scaleConfig_ [] = "scale" .= A.Null  -- not sure here-scaleConfig_ scs = "scale" .= object (map scaleConfigProperty scs)---legendProp_ :: [LegendProperty] -> LabelledSpec-legendProp_ [] = "legend" .= A.Null-legendProp_ lps = "legend" .= object (map legendProperty lps)---value_ :: T.Text -> LabelledSpec-value_ v = "value" .= v---selCond_ :: (a -> [LabelledSpec]) -> BooleanOp -> [a] -> [a] -> [LabelledSpec]-selCond_ getProps selName ifClause elseClause =-  let h = ("condition", hkey)-      toProps = concatMap getProps-      hkey = object (("selection", booleanOpSpec selName) : toProps ifClause)-      hs = toProps elseClause-  in h : hs---- Special case the single-condition check, so that I don't get false--- positives when comparing against the Vega-Lite specification. There--- should be no actionable difference from this special case (i.e.--- the output being '[object]' and 'object' have the same meaning).------ There is also the simplification to replace---      test: { selection: xxx }--- by---      selection: xxx--- which happens for the Selection operator.----dataCond_ :: (a -> [LabelledSpec]) -> [(BooleanOp, [a])] -> [a] -> [LabelledSpec]-dataCond_ getProps tests elseClause =-  let h = ("condition", condClause)-      condClause = case conds of-                     [cond] -> cond-                     _ -> toJSON conds-      conds = map testClause tests-      testClause (Selection sel, ifClause) =-        object (("selection" .= sel) : toProps ifClause)-      testClause (predicate, ifClause) =-        object (("test", booleanOpSpec predicate) : toProps ifClause)-      toProps = concatMap getProps-      hs = toProps elseClause-  in h : hs----fromT :: T.Text -> VLSpec-fromT = toJSON--fromF :: Double -> VLSpec-fromF = toJSON---------------- | A Vega Lite visualization, created by---   'toVegaLite'. The contents can be extracted with 'fromVL'.----newtype VegaLite =-  VL {-  fromVL :: VLSpec-  -- ^ Extract the specification for passing to a VegaLite visualizer.-  ---  --   > let vlSpec = fromVL vl-  --   > Data.ByteString.Lazy.Char8.putStrLn (Data.Aeson.Encode.Pretty.encodePretty vlSpec)-  ---  --   Note that there is __no__ validation done to ensure that the-  --   output matches the Vega Lite schema. That is, it is possible to-  --   create an invalid visualization with this module (e.g. missing a-  --   data source or referring to an undefined field).-  }---- | The Vega-Lite specification is represented as JSON.-type VLSpec = Value--baseSchema :: T.Text-baseSchema = "https://vega.github.io/schema/vega-lite/"---- | The latest version 2 Vega-Lite schema (equivalent to---   @'vlSchema' 2 Nothing Nothing Nothing@).-vlSchema2 :: T.Text-vlSchema2 = vlSchema 2 Nothing Nothing Nothing---- | The latest version 3 Vega-Lite schema (equivalent to---   @'vlSchema' 3 Nothing Nothing Nothing@).-vlSchema3 :: T.Text-vlSchema3 = vlSchema 3 Nothing Nothing Nothing---- | The latest version 4 Vega-Lite schema (equivalent to---   @'vlSchema' 4 Nothing Nothing Nothing@).-vlSchema4 :: T.Text-vlSchema4 = vlSchema 4 Nothing Nothing Nothing---- | Create the Vega-Lite schema for an arbitrary version. See---   <https://github.com/vega/schema> for more information on naming---   and availability.------   There is no validation of the input values.------   At the time of writing the latest version 4 schema - which---   is @https://vega.github.io/schema/vega-lite/v4.0.0-beta.0.json@ ----   can be specified as------   @vlSchema 4 (Just 0) (Just 0) (Just "-beta.0")@------   whereas------   @vlSchema 4 Nothing Nothing Nothing@------   refers to the latest version.----vlSchema ::-  Natural-  -- ^ The major version-  -> Maybe Natural-  -- ^ The minor version-  -> Maybe Natural-  -- ^ The \"micro\" version-  -> Maybe T.Text-  -- ^ Anything beyond "major.minor.micro" (e.g. \"-beta.0").-  -> T.Text-  -- ^ The Vega-Lite Schema-vlSchema major mminor mmicro mextra =-  let versions = [ pure (showNat major)-                 , showNat <$> mminor-                 , showNat <$> mmicro-                 ]-      version = T.intercalate "." (catMaybes versions)--  in baseSchema <> "v" <> version <> fromMaybe "" mextra <> ".json"---showNat :: Natural -> T.Text-showNat = T.pack . show---{-|--Convert a list of Vega-Lite specifications into a single JSON object-that may be passed to Vega-Lite for graphics generation. Commonly-these will include at least a data, mark, and encoding specification.--While simple properties like 'mark' may be provided directly, it is-usually clearer to label more complex ones such as encodings as-separate expressions. This becomes increasingly helpful for-visualizations that involve composition of layers, repeats and facets.--Specifications can be built up by chaining a series of functions (such-as 'dataColumn' or 'position' in the example below). Functional-composition using the '.' operator allows this to be done compactly.--@-let dat = 'dataFromColumns' []-          . 'dataColumn' "a" ('Strings' [ \"C", \"C", \"D", \"D", \"E", \"E" ])-          . 'dataColumn' "b" ('Numbers' [ 2, 7, 1, 2, 6, 8 ])--    enc = 'encoding'-          . 'position' 'X' [ 'PName' "a", 'PmType' 'Nominal' ]-          . 'position' 'Y' [ 'PName' "b", 'PmType' 'Quantitative', 'PAggregate' 'Mean' ]--in 'toVegaLite' [ dat [], 'mark' 'Bar' [], enc [] ]-@--The schema used is <https://github.com/vega/schema version 3 of Vega-Lite>,-although there are some differences, in part because of bugs in @hvega@ --in which case please [report an issue](https://github.com/DougBurke/hvega/issues) - but also because of issues with the Vega-Lite spec (for instance there-are several minor issues I have reported against version 3.3.0 of the-Vega-Lite schema).--Use 'toVegaLiteSchema' if you need to create a Vega-Lite specification-which uses a different version of the schema.---}---- TODO:---    Should the input data, or converted to VLSpec, be stored---    without the $schema key, so it can be easily combined with---    other visualizations?------    Could we make VegaLite a Semigroup so you can easily combine---    specifications? However, what would that mean (concatenation,---    if so what direction, anything else?)--toVegaLite :: [PropertySpec] -> VegaLite-toVegaLite = toVegaLiteSchema vlSchema3---{-|-A version of 'toVegaLite' that allows you to change the Vega-Lite-schema version of the visualization.--@-'toVegaLiteSchema' 'vlSchema4' props-@--}--toVegaLiteSchema ::-  T.Text-  -- ^ The schema to use (e.g. 'vlSchema4' or created with 'vlSchema').-  -> [PropertySpec]-  -- ^ The visualization.-  -> VegaLite-toVegaLiteSchema schema props =-  let kvals = ("$schema" .= schema) : map toProp props-      toProp = first vlPropertyLabel--  in VL { fromVL = object kvals }---{-|--Combines a list of labelled specifications into a single specification.-This is useful when you wish to create-a single page with multiple visulizualizations.--@-'combineSpecs'-    [ ( "vis1", myFirstVis )-    , ( "vis2", mySecondVis )-    , ( "vis3", myOtherVis )-    ]-@--}-combineSpecs :: [LabelledSpec] -> VLSpec-combineSpecs = object--{-|--Converts VegaLite to html Text. Uses Vega-Embed with the-default options. See 'toHtmlWith' for more control.--@since 0.2.1.0--}-toHtml :: VegaLite -> TL.Text-toHtml = toHtmlWith Nothing--{-|--Converts VegaLite to an html file. Uses Vega-Embed with the-default options. See 'toHtmlFileWith' for more control.--@since 0.2.1.0--}-toHtmlFile :: FilePath -> VegaLite -> IO ()-toHtmlFile file = TL.writeFile file . toHtml--{-|--Converts VegaLite to html Text. Uses Vega-Embed and is for when-some control is needed over the output: 'toHtml' is a simpler-form which just uses the default Vega-Embed options.--The render you use to view the output file must support Javascript,-since it is needed to create the visualization from the Vega-Lite-specification. The Vega and Vega-Lite Javascript versions are pegged-to 5 and 3, but no limit is applied to the Vega-Embed library.--@since 0.4.0.0--}-toHtmlWith ::-  Maybe Value-  -- ^ The options to pass to the Vega-Embed @embed@ routine. See-  --   <https://github.com/vega/vega-embed#options> for the-  --   supported options.-  -> VegaLite-  -- ^ The Vega-Lite specification to display.-  -> TL.Text-toHtmlWith mopts vl =-  let spec = A.encodeToLazyText (fromVL vl)-      opts = maybe "" (\o -> "," <> A.encodeToLazyText o) mopts--  in TL.unlines-    [ "<!DOCTYPE html>"-    , "<html>"-    , "<head>"-      -- versions are fixed at vega 5, vega-lite 3-    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega@5\"></script>"-    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega-lite@3\"></script>"-    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega-embed\"></script>"-    , "</head>"-    , "<body>"-    , "<div id=\"vis\"></div>"-    , "<script type=\"text/javascript\">"-    , "  var spec = " <> spec <> ";"-    , "  vegaEmbed(\'#vis\', spec" <> opts <> ").then(function(result) {"-    , "  // Access the Vega view instance (https://vega.github.io/vega/docs/api/view/) as result.view"-    , "  }).catch(console.error);"-    , "</script>"-    , "</body>"-    , "</html>"-    ]--{-|--Converts VegaLite to an html file. Uses Vega-Embed and is for when-some control is needed over the output: 'toHtmlFile' is a simpler-form which just uses the default Vega-Embed options.--@since 0.4.0.0--}-toHtmlFileWith ::-  Maybe Value-  -- ^ The options to pass to the Vega-Embed @embed@ routine. See-  --   <https://github.com/vega/vega-embed#options> for the-  --   supported options.-  -> FilePath-  -- ^ The output file name (it will be over-written if it already exists).-  -> VegaLite-  -- ^ The Vega-Lite specification to display.-  -> IO ()-toHtmlFileWith mopts file = TL.writeFile file . toHtmlWith mopts---{-|--Create a specification sufficient to define an element in a composed visualization-such as a superposed layer or juxtaposed facet. Typically a layer will contain a-full set of specifications that define a visualization with-the exception of the data specification which is usually defined outside of any one-layer. Whereas for repeated and faceted specs, the entire specification is provided.--@-spec1 = asSpec [ enc1 [], 'mark' 'Line' [] ]-@--}-asSpec :: [PropertySpec] -> VLSpec-asSpec = object . map (first vlPropertyLabel)---{-|--Specifies a list of geo features to be used in a geoShape specification.-Each feature object in this collection can be created with the 'geometry'-function.--@-'geoFeatureCollection'-    [ 'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( -3, 52 ), ( 4, 52 ), ( -3, 59 ) ] ])-        [ ( "myRegionName", 'Str' "Northern region" ) ]-    , 'geometry' ('GeoPolygon' [ [ ( -3, 52 ), ( 4, 52 ), ( 4, 45 ), ( -3, 52 ) ] ])-        [ ( "myRegionName", 'Str' "Southern region" ) ]-    ]-@--}-geoFeatureCollection :: [VLSpec] -> VLSpec-geoFeatureCollection geoms =-  object [ type_ "FeatureCollection"-         , "features" .=  geoms-         ]---{-|--Specifies a list of geometry objects to be used in a geoShape specification.-Each geometry object in this collection can be created with the 'geometry'-function.--@-'geometryCollection'-    [ 'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []-    , 'geometry' ('GeoPoint' -3.5 55.5) []-    ]-@--}-geometryCollection :: [VLSpec] -> VLSpec-geometryCollection geoms =-  object [ type_ "GeometryCollection"-         , "geometries" .= geoms-         ]---{-|--Create a named aggregation operation on a field that can be added to a transformation.-For further details see the-<https://vega.github.io/vega-lite/docs/aggregate.html#aggregate-op-def Vega-Lite documentation>.--@-'transform'-    . 'aggregate'-        [ 'opAs' 'Min' "people" "lowerBound"-        , 'opAs' 'Max' "people" "upperBound"-        ]-        [ "age" ]-@--}-opAs ::-  Operation-  -- ^ The aggregation operation to use.-  -> T.Text-  -- ^ The name of the field which is to be aggregated (when the operation-  --   is 'Count' leave as the empty string).-  -> T.Text-  -- ^ The name given to the transformed data.-  -> VLSpec---- The Count case is special-cased purely to make it easier to compare--- the hvega output against the Veg-Lite examples. There should be no--- semantic difference here.----opAs Count _ label =-  object [ op_ Count, "as" .= label ]-opAs op field label =-  object [ op_ op, field_ field, "as" .= label ]---{-|--Top-level Vega-Lite properties. These are the ones that define the core of the-visualization grammar. All properties are created by functions which can be-arranged into seven broad groups:--[Data Properties] These relate to the input data to be visualized. Generated by-'dataFromColumns', 'dataFromRows', 'dataFromUrl', 'dataFromSource',-'dataFromJson', 'dataSequence', 'sphere', and 'graticule'.--[Transform Properties] These indicate that some transformation of input data should-be applied before encoding them visually. Generated by 'transform'-and 'projection' they can include data transformations such as 'filter',-'binAs' and 'calculateAs' and geo transformations of longitude, latitude coordinates-used by marks such as 'Geoshape', 'Point', and 'Line'.--[Mark Properties] These relate to the symbols used to visualize data items. They-are generated by 'mark', and include types such as 'Circle', 'Bar', and 'Line'.--[Encoding Properties] These specify which data elements are mapped to which mark characteristics-(known as /channels/). Generated by 'encoding', they include encodings-such as 'position', 'color', 'size', 'shape', 'text', 'hyperlink', and-'order'.--[Composition Properties] These allow visualization views to be combined to form more-complex visualizations. Generated by 'layer', 'repeat', 'repeatFlow', 'facet', 'facetFlow',-'vlConcat', 'columns', 'hConcat', 'vConcat', 'asSpec', and 'resolve'.--[Interaction Properties] These allow interactions such as clicking, dragging and others-generated via a GUI or data stream to influence the visualization. Generated by-'selection'.--[Supplementary and Configuration Properties] These provide a means to add metadata and-styling to one or more visualizations. Generated by 'name', 'title', 'description',-'background', 'height', 'width', 'padding', 'autosize', 'viewBackground',-and 'configure'.--Prior to @0.4.0.0@ this was an opaque data type, as the constructors-were not exported. It is suggested that you do not import the-constructors to @VLProperty@ unless you need to transform the-Vega-Lite code in some manner (e.g. because @hvega@ is missing needed-functionality or is buggy).--Note that there is only a very-limited attempt to enforce the Vega-Lite-Schema (e.g. to ensure the required components are provided).---}---- based on schema 3.3.0 #/definitions/TopLevelSpec--- which accepts one of---    #/definitions/TopLevelUnitSpec---    #/definitions/TopLevelFacetSpec---    #/definitions/TopLevelLayerSpec---    #/definitions/TopLevelRepeatSpec---    #/definitions/TopLevelConcatSpec---    #/definitions/TopLevelVConcatSpec---    #/definitions/TopLevelHConcatSpec--data VLProperty-    = VLAlign-      -- ^ See 'align'.-      ---      --   @since 0.4.0.0-    | VLAutosize-      -- ^ See 'autosize'.-    | VLBackground-      -- ^ See 'background'.-    | VLBounds-      -- ^ See 'bounds'.-      ---      --   @since 0.4.0.0-    | VLCenter-      -- ^ See 'center' and 'centerRC'.-      ---      --   @since 0.4.0.0-    | VLColumns-      -- ^ See 'columns'.-      ---      --   @since 0.4.0.0-    | VLConcat-      -- ^ See 'vlConcat'.-      ---      --   @since 0.4.0.0-    | VLConfig-      -- ^ See 'configure'.-    | VLData-      -- ^ See 'dataFromColumns', 'dataFromJson', 'dataFromRows',-      --   'dataFromSource', 'dataFromUrl', 'dataName', 'dataSequence',-      --   'dataSequenceAs', 'graticule', 'noData', and 'sphere'.-    | VLDatasets-      -- ^ See 'datasets'.-    | VLDescription-      -- ^ See 'description'.-    | VLEncoding-      -- ^ See 'encoding'.-    | VLFacet-      -- ^ See 'facet' and 'facetFlow'.-    | VLHConcat-      -- ^ See 'hConcat'.-    | VLHeight-      -- ^ See 'height'.-    | VLLayer-      -- ^ See 'layer'.-    | VLMark-      -- ^ See 'mark'.-    | VLName-      -- ^ See 'name'.-    | VLPadding-      -- ^ See 'padding'.-    | VLProjection-      -- ^ See 'projection'.-    | VLRepeat-      -- ^ See 'repeat' and 'repeatFlow'.-    | VLResolve-      -- ^ See 'resolve'.-    | VLSelection-      -- ^ See 'selection'.-    | VLSpacing-      -- ^ See 'alignRC', 'spacing', and 'spacingRC'.-      ---      --   @since 0.4.0.0-    | VLSpecification-      -- ^ See 'specification'.-    | VLTitle-      -- ^ See 'title'.-    | VLTransform-      -- ^ See 'transform'.-    | VLUserMetadata-      -- ^ see 'usermetadata'.-      ---      --   @since 0.4.0.0-    | VLVConcat-      -- ^ See 'vConcat'.-    | VLViewBackground-      -- ^ See 'viewBackground'.-      ---      --   @since 0.4.0.0-    | VLWidth-      -- ^ See 'width'.---vlPropertyLabel :: VLProperty -> T.Text-vlPropertyLabel VLAlign = "align"-vlPropertyLabel VLAutosize = "autosize"-vlPropertyLabel VLBackground = "background"-vlPropertyLabel VLBounds = "bounds"-vlPropertyLabel VLCenter = "center"-vlPropertyLabel VLColumns = "columns"-vlPropertyLabel VLConcat = "concat"-vlPropertyLabel VLConfig = "config"-vlPropertyLabel VLData = "data"-vlPropertyLabel VLDatasets = "datasets"-vlPropertyLabel VLDescription = "description"-vlPropertyLabel VLEncoding = "encoding"-vlPropertyLabel VLFacet = "facet"-vlPropertyLabel VLHConcat = "hconcat"-vlPropertyLabel VLHeight = "height"-vlPropertyLabel VLLayer = "layer"-vlPropertyLabel VLMark = "mark"-vlPropertyLabel VLName = "name"-vlPropertyLabel VLPadding = "padding"-vlPropertyLabel VLProjection = "projection"-vlPropertyLabel VLRepeat = "repeat"-vlPropertyLabel VLResolve = "resolve"-vlPropertyLabel VLSelection = "selection"-vlPropertyLabel VLSpacing = "spacing"-vlPropertyLabel VLSpecification = "spec"-vlPropertyLabel VLTitle = "title"-vlPropertyLabel VLTransform = "transform"-vlPropertyLabel VLUserMetadata = "usermeta"-vlPropertyLabel VLVConcat = "vconcat"-vlPropertyLabel VLViewBackground = "view"-vlPropertyLabel VLWidth = "width"---{-|--Indicates the type of data to be parsed when reading input data. For @FoDate@-and @FoUtc@, the formatting specification can be specified using-<https://vega.github.io/vega-lite/docs/data.html#format D3's formatting specifiers>-or left as an empty string if default date formatting is to be applied. Care should-be taken when assuming default parsing of dates because different browsers can-parse dates differently. Being explicit about the date format is usually safer.---}-data DataType-    = FoNumber-      -- ^ Indicate numeric data type to be parsed when reading input data.-    | FoBoolean-      -- ^ Indicate Boolean data type to be parsed when reading input data.-    | FoDate T.Text-      -- ^ Date format for parsing input data using-      --   [D3's formatting specifiers](https://vega.github.io/vega-lite/docs/data.html#format)-      --   or left as an empty string for default formatting.-    | FoUtc T.Text-      -- ^ Similar to 'FoDate' but for UTC format dates.---{-|--Specifies the type of format a data source uses. If the format is indicated by-the file name extension (@".tsv"@, @".csv"@, @".json"@) there is no need to indicate the-format explicitly. However this can be useful if the filename extension does not-indicate type (e.g. @".txt"@) or you wish to customise the parsing of a file. For-example, when specifying the @JSON@ format, its parameter indicates the name of-property field containing the attribute data to extract. For details see the-<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>.--}-data Format-    = JSON T.Text-      -- ^ Property to be extracted from some JSON when it has some surrounding structure.-      --   e.g., specifying the property @values.features@ is equivalent to retrieving-      --   @json.values.features@ from a JSON object with a custom delimiter.-    | CSV-      -- ^ Comma-separated (CSV) data file format.-    | TSV-      -- ^ Tab-separated (TSV) data file format-    | DSV Char-      -- ^ The fields are separated by the given character (which must be a-      --   single 16-bit code unit).-      ---      --   @since 0.4.0.0-      {- This isn't in the current vega-lite v3 schema as far as I can see-    | Arrow-      -- ^ <https://observablehq.com/@theneuralbit/introduction-to-apache-arrow Apache Arrow> format.-      ---      -- @since 0.4.0.0-      -}-    | TopojsonFeature T.Text-      -- ^ A topoJSON feature format containing an object with the given name. For example:-      ---      -- @-      -- 'dataFromUrl' \"londonBoroughs.json\" ['TopojsonFeature' \"boroughs\"]-      -- @-    | TopojsonMesh T.Text-      -- ^ A topoJSON mesh format containing an object with the given name. Unlike-      --   'TopojsonFeature', the corresponding geo data are returned as a single unified mesh,-      --   not as individual GeoJSON features.-    | Parse [(T.Text, DataType)]-      -- ^ Parsing rules when processing some data text, specified as-      --   a list of tuples in the form @(fieldname,-      --   datatype)@. Useful when automatic type inference needs to-      --   be overridden, for example when converting integers representing-      --   years into dates and strings into numbers:-      ---      -- @-      -- 'dataFromUrl' \"myDataFile.csv\"-      --    [ 'Parse' [ ( \"year\", 'FoDate' \"%Y\" ), ( "\y\", 'FoNumber' ) ] ]-      -- @---{-|--A convenience type-annotation label. It is the same as 'Data'.--@since 0.4.0.0--}-type PropertySpec = (VLProperty, VLSpec)--{-|--Represents a named Vega-Lite specification, usually generated by a-function in this module. You shouldn't need to create @LabelledSpec@-tuples directly, but they can be useful for type annotations.--}-type LabelledSpec = (T.Text, VLSpec)--{-|--Represent those functions which can be chained together using function-composition to append new specifications onto an existing list.--}-type BuildLabelledSpecs = [LabelledSpec] -> [LabelledSpec]--{-|--Represents a single column of data. Used when generating inline data with-'dataColumn' and 'dataFromColumns'.--}-type DataColumn = [LabelledSpec]--{-|--Represents a single row of data. Used when generating inline data with-'dataRow' and 'dataFromRows'.--}-type DataRow = VLSpec--{-|--Convenience type-annotation label for use with data generation functions.--@-myRegion : ['DataColumn'] -> 'Data'-myRegion =-    'dataFromColumns' []-        . 'dataColumn' "easting" ('Numbers' [ -3, 4, 4, -3, -3 ])-        . 'dataColumn' "northing" ('Numbers' [ 52, 52, 45, 45, 52 ])-@--It is the same as 'PropertySpec' (which was added in @0.4.0.0@),-but kept separate to help better-document code.---}-type Data = (VLProperty, VLSpec)---{-|--Convenience type-annotation label to indicate a color value.-There is __no attempt__ to validate that the user-supplied input-is a valid color.--Any supported HTML color specification can be used, such as:--@-\"#eee\"-\"#734FD8\"-\"crimson\"-\"rgb(255,204,210)\"-\"hsl(180, 50%, 50%)\"-@--@since 0.4.0.0--}--type Color = T.Text---{-|--Convenience type-annotation label to indicate an opacity value, which-lies in the range 0 to 1 inclusive. There is __no attempt__ to validate-that the user-supplied value falls in this range.--A value of 0 indicates fully transparent (see through), and 1 is-fully opaque (does not show anything it is on top of).--@since 0.4.0.0--}--type Opacity = Double---{-|--Convenience type-annotation label to indicate an angle, which is measured-in degrees from the horizontal (so anti-clockwise).--The value should be in the range 0 to 360, inclusive, but __no attempt__ is-made to enforce this.--@since 0.4.0.0--}--type Angle = Double---{-|--At what "depth" (z index) is the item to be drawn (a relative depth-for items in the visualization). The standard values are @0@ for-back and @1@ for front, but other values can be used if you want-to ensure a certain layering of items.--The following example is taken from a discussion with-<https://github.com/gicentre/elm-vegalite/issues/15#issuecomment-524527125 Jo Wood>:--@-let dcols = 'dataFromColumns' []-              . 'dataColumn' "x" ('Numbers' [ 20, 10 ])-              . 'dataColumn' "y" ('Numbers' [ 10, 20 ])-              . 'dataColumn' "cat" ('Strings' [ "a", "b" ])--    axis lbl z = [ 'PName' lbl, 'PmType' 'Quantitative', 'PAxis' [ 'AxZIndex' z ] ]-    enc = 'encoding'-            . 'position' 'X' (axis "x" 2)-            . 'position' 'Y' (axis "y" 1)-            . 'color' [ 'MName' "cat", 'MmType' 'Nominal', 'MLegend' [] ]--    cfg = 'configure'-            . 'configuration' ('Axis' [ 'GridWidth' 8 ])-            . 'configuration' ('AxisX' [ 'GridColor' "red" ])-            . 'configuration' ('AxisY' [ 'GridColor' "blue" ])--in 'toVegaLite' [ cfg []-              , dcols []-              , enc []-              , 'mark' 'Circle' [ 'MSize' 5000, 'MOpacity' 1 ]-              ]-@--<<images/zindex.png>>--<https://vega.github.io/editor/#/url/vega-lite/N4KABBYEQMYPYDsBmBLA5lAXGUk-QEMAPFAZwE0sdx9ao0AnFAEwGE4AbOBqqAIw4BXAKZQatAL4AacfijEyADSq5acxi3Zce2KA2HMxasNNl55JUirNr6TZgHUWAFwAWVABw2IE2afMAtgQMANbWxlCkKABeotgArAAMyTIRcAAOBDAozgCeVACMqbZ56XHQ2QwwHKJ+xRBQzATOBOG2AG4EQsJW2ADa3viqxnQwzbyt9SPmRFQATIlT0w352AWJg3j+y8PLDWPOvHxQS8tQs2uLm7arYAvXPoMAunWyUAAkpDCuwkG8rs5nOlSJgAPSg9rCNAEAB0aByrkEfBhKDgoK+PyCEKhBAAtBwcsIIQBmGEAK1IiBOb2ECHgzBQCAw2F25ng2ja0ygqGEHEMugO1L2UFK5SgCDgAUZXSFZxqaFp-LACEEHA4g22dAu1GFPL5vFmpzoot4AEdBAQEM4cs0UJDZVyFL0dXtIFBoozmMJtXMHiYNUboLdWbY9UqoPlA+YTbpzZbrS1rfao26nZzXe7Pd7Cn7fMY85BfL4gA View the visualization in the Vega Editor>--@since 0.4.0.0--}--type ZIndex = Natural---formatProperty :: Format -> [LabelledSpec]-formatProperty (JSON js) =-  let ps = [("type", "json")]-           <> if T.null (T.strip js) then [] else [("property", js)]-  in map (second toJSON) ps--formatProperty CSV = [("type", "csv")]-formatProperty TSV = [("type", "tsv")]-formatProperty (DSV delim) = [("type", "dsv"), "delimiter" .= delim]--- formatProperty Arrow = [("type", "arrow")]-formatProperty (TopojsonFeature os) = [("type", "topojson")-                                      , "feature" .= os-                                      ]-formatProperty (TopojsonMesh os) = [("type", "topojson")-                                   , "mesh" .= os-                                   ]-formatProperty (Parse fmts) =-  let pObj = object (map (second dataTypeSpec) fmts)-  in [("parse", pObj)]---dataTypeSpec :: DataType -> VLSpec-dataTypeSpec dType =-  let s = case dType of-        FoNumber -> "number"-        FoBoolean -> "boolean"-        FoDate fmt | T.null fmt -> "date"-                   | otherwise -> "date:'" <> fmt <> "'"-        FoUtc fmt | T.null fmt -> "utc"-                  | otherwise -> "utc:'" <> fmt <> "'"-  in toJSON s---{-|--Create a row of data. A row comprises a list of (columnName, value) pairs.-The final parameter is the list of any other rows to which this is added.--This is expected to be used with 'dataFromRows'.--@-'dataRow' [(\"Animal\", 'Str' \"Fish\"), (\"Age\", 'Number' 28), (\"Year\", 'Str' "2010")] []-@--}-dataRow :: [(T.Text, DataValue)] -> [DataRow] -> [DataRow]-dataRow rw = (object (map (second dataValueSpec) rw) :)---{-|--Create a dataset comprising a collection of named 'Data' items. Each data item-can be created with normal data generating functions such as 'dataFromRows' or-'dataFromJson'. These can be later referred to using 'dataFromSource'.--@-let toJS = Data.Aeson.toJSON-    obj = Data.Aeson.object--    dvals = 'dataFromRows' []-            . 'dataRow' [ ( "cat", 'Str' "a" ), ( "val", 'Number' 10 ) ]-            . 'dataRow' [ ( "cat", 'Str' "b" ), ( "val", 'Number' 18 ) ]-    json = toJS-            [ obj [ ( "cat", toJS "a" ), ( "val", toJS 120 ) ]-            , obj [ ( "cat", toJS "b" ), ( "val", toJS 180 ) ]-            ]--    enc = ...--in 'toVegaLite'-    [ 'datasets' [ ( \"myData\", dvals [] ),  ( \"myJson\", 'dataFromJson' json [] ) ]-    , 'dataFromSource' \"myData\" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-datasets :: [(T.Text, Data)] -> Data-datasets namedData =-  -- Follow Elm in parsing the structure to get what we want, but the code is-  -- written rather differently.-  ---  -- The input is expected to be a singleton list containing a pair.-  let converted = extract . snd-      specs = map (second converted) namedData--      convert :: Value -> Maybe [(T.Text, Value)]-      convert v = HM.toList <$> decode (encode v)--      extract din =-        let extract' [(_, v)] = Just v-            extract' _ = Nothing--        in fromMaybe din (convert din >>= extract')--  in (VLDatasets, object specs)----- | This is for composed specifications, and it tells the visualization to---   ignore the data from the parent.------   @since 0.4.0.0-noData :: Data-noData = (VLData, A.Null)---{-|--Name to give a data source. Useful when a specification needs to reference a-data source, such as one generated via an API call.--@-dvals = 'dataName' \"myName\" ('dataFromUrl' \"myData.json\" [])-@--@since 0.4.0.0---}---- TODO: can we restrict this to only those with a VLProperty of VLData?--dataName ::-  T.Text-  -- ^ The name to give the data source-  -> Data-  -- ^ The data source to be named.-  -> Data-  -- ^ If the input @Data@ argument is not a data source then-  --   this is just the input value.-dataName s odata@(_, dataSpec) =-  -- follow Elm in parsing the structure to get what we want, but the code is-  -- written rather differently. This is based on the code used in datasets.-  ---  -- The input is expected to be a singleton list containing a pair.-  ---  let converted = convert >>= extract--      -- Aeson's objects are wrappers around a hash map, so this should be-      -- a relatively easy conversion. The type annotation isn't needed-      -- but left in for reference.-      ---      convert :: Maybe [(T.Text, Value)]-      convert = HM.toList <$> decode (encode dataSpec)--      extract [v] = Just v-      extract _ = Nothing--  in case converted of-       Just v -> (VLData, object [ "name" .= s, v ])-       _ -> odata---{-|--Generate a sequence of numbers as a data source. The resulting-sequence will have the name @\"data\"@. To give it an alternative name use-'dataSequenceAs'.--@-myData = 'dataSequence' 0 6.28 0.1-@--@since 0.4.0.0---}-dataSequence ::-  Double     -- ^ start of the sequence (inclusive)-  -> Double  -- ^ end of the sequence (exclusive)-  -> Double  -- ^ step size-  -> Data-dataSequence start stop step =-  let vals = [("sequence", object svals)]-      svals = [ "start" .= start-              , "stop" .= stop-              , "step" .= step-              ]--  in (VLData, object vals)---{-|--Generate a sequence of numbers as a named data source. This extends-'dataSequence' by allowing you to name the data source.--@-myTheta = 'dataSequenceAs' 0 6.28 0.1 \"theta\"-@--@since 0.4.0.0---}-dataSequenceAs ::-  Double     -- ^ start of the sequence (inclusive)-  -> Double  -- ^ end of the sequence (exclusive)-  -> Double  -- ^ step size-  -> T.Text  -- ^ The name of the data source-  -> Data-dataSequenceAs start stop step outName =-  let vals = [("sequence", object svals)]-      svals = [ "start" .= start-              , "stop" .= stop-              , "step" .= step-              , "as" .= outName-              ]--  in (VLData, object vals)---{-|--Declare a data source from a list of column values. Each column has a-specific type (e.g. 'Number' or 'String'), but different columns can have-different types.--Note that the columns are truncated to match the length of the shortest column.--@-'dataFromColumns' [ 'Parse' [ ( \"Year\", 'FoDate' "%Y" ) ] ]-  . 'dataColumn' \"Animal\" ('Strings' [ \"Fish\", \"Dog\", \"Cat\" ])-  . 'dataColumn' \"Age\" ('Numbers' [ 28, 12, 6 ])-  . 'dataColumn' \"Year\" ('Strings' [ "2010", "2014", "2015" ])-@--}-dataFromColumns ::-  [Format]-  -- ^ An optional list of formatting instructions for the columns.-  ---  --   Simple numbers and strings do not normally need formatting, but it is-  --   good practice to explicitly declare date-time formats as handling of-  --   these values can vary between different viewers (e.g. browsers).-  ---  --   See the-  --   <https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>-  --   for more details.-  -> [DataColumn]-  -- ^ The columns to add. This is expected to be created with one or more-  --   calls to 'dataColumn'.-  -> Data-dataFromColumns fmts cols =-  let dataArray = map object (transpose cols)--      vals = [("values", toJSON dataArray)]-             <> if null fmts-                then []-                else [("format", toJSON fmtObject)]--      fmtObject = object (concatMap formatProperty fmts)--  in (VLData, object vals)---transpose :: [[a]] -> [[a]]-transpose [] = []-transpose ([]:xss) = transpose xss-transpose ((x:xs) : xss) =-  let heads = filterMap elmHead xss ---      tails = filterMap elmTail xss--      elmHead (h:_) = Just h-      elmHead [] = Nothing--      elmTail [] = Nothing-      elmTail (_:ts) = Just ts--      filterMap = mapMaybe--  in (x : heads) : transpose (xs : tails)---{-|--Declare a data source from a provided json specification. The most likely use-case-for specifying json inline is when creating <http://geojson.org geojson> objects,-when 'geometry', 'geometryCollection', and 'geoFeatureCollection' functions-may be used. For more general cases of json creation, consider 'Data.Aeson.encode'.--@-let geojson =-        'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []-in 'toVegaLite'-    [ 'width' 200-    , 'height' 200-    , 'dataFromJson' geojson []-    , 'projection' [ 'PrType' 'Orthographic' ]-    , 'mark' 'Geoshape' []-    ]-@--}-dataFromJson :: VLSpec -> [Format] -> Data-dataFromJson vlspec fmts =-  let js = if null fmts-           then object [("values", vlspec)]-           else object [ ("values", vlspec)-                       , ("format",-                          object (concatMap formatProperty fmts)) ]-  in (VLData, js)---{-|--A single data value. This is used when a function or constructor-can accept values of different types (e.g. either a number or a string),-such as:-'dataRow', 'geometry', many constructors of the 'Filter' type,-'ImNewValue', and 'SInit'.---}-data DataValue-    = Boolean Bool-    | DateTime [DateTime]-    | Number Double-    | Str T.Text-    | NullValue-      -- ^ Create a JavaScript @null@ value. This can be useful when-      --   explictly recoding a value as undefined, such as in the following-      --   example:-      ---      --   @-      --   'dataFromRows' []-      --     . 'dataRow' [("x", 'Number' 1), ("y", 'String' "good")]-      --     . 'dataRow' [("x", 'Number' 2), ("y", 'NullValue')]-      --     . 'dataRow' [("x", 'Number' 3), ("y", 'String' "bad")]-      --   @-      ---      --   For more-complex data sources - such as lists of defined-      --   and un-specified values, it is suggested that 'dataFromJson'-      --   be used rather than 'dataFromRows' or 'dataFromColumns'.-      ---      --   @since 0.4.0.0--dataValueSpec :: DataValue -> VLSpec-dataValueSpec (Boolean b) = toJSON b-dataValueSpec (DateTime dt) = object (map dateTimeProperty dt)-dataValueSpec (Number x) = toJSON x-dataValueSpec (Str t) = toJSON t-dataValueSpec NullValue = A.Null---{-|--A list of data values. This is used when a function or constructor-can accept lists of different types (e.g. either a list of numbers-or a list of strings), such as:-'dataColumn', 'CustomSort', 'FOneOf', or 'ImKeyVals'.--If your data contains undefined values then it is suggested that-you convert it to JSON (e.g. 'Value') and then use 'dataFromJson'.---}-data DataValues-    = Booleans [Bool]-    | DateTimes [[DateTime]]-    | Numbers [Double]-    | Strings [T.Text]---dataValuesSpecs :: DataValues -> [VLSpec]-dataValuesSpecs (Booleans bs) = map toJSON bs-dataValuesSpecs (DateTimes dtss) = map (object . map dateTimeProperty) dtss-dataValuesSpecs (Numbers xs) = map toJSON xs-dataValuesSpecs (Strings ss) = map toJSON ss--{-|--Create a column of data. A column has a name and a list of values. The final-parameter is the list of any other columns to which this is added.--This is expected to be used with 'dataFromColumns'.--@-'dataColumn' \"Animal\" ('Strings' [ \"Cat\", \"Dog\", \"Mouse\"]) []-@--}-dataColumn :: T.Text -> DataValues -> [DataColumn] -> [DataColumn]-dataColumn colName dVals xs =-  let col = case dVals of-        Booleans cs -> map toJSON cs-        DateTimes cs -> map dtToJSON cs-        Numbers cs -> map toJSON cs-        Strings cs -> map toJSON cs--      dtToJSON = object . map dateTimeProperty-      x = map (colName,) col--  in x : xs---{-|--Declare a data source from a provided list of row values. Each row-contains a list of tuples where the first value is a string-representing the column name, and the second the column value for that-row. Each column can have a value of a different type but-__you must ensure__-that when subsequent rows are added, they match the types of-previous values with shared column names.--Note though that generally if you are creating data inline (as opposed-to reading from a file), adding data by column is more efficient and-less error-prone.--@-dataFromRows [ 'Parse' [ ( \"Year\", 'FoDate' "%Y" ) ] ]-  . 'dataRow' [ ( \"Animal\", 'Str' \"Fish\" ), ( \"Age\", 'Number' 28 ), ( \"Year\", 'Str' "2010" ) ]-  . 'dataRow' [ ( \"Animal\", 'Str' \"Dog\" ), ( \"Age\", 'Number' 12 ), ( \"Year\", 'Str' "2014" ) ]-  . 'dataRow' [ ( \"Animal\", 'Str' \"Cat\" ), ( \"Age\", 'Number' 6 ), ( \"Year\", 'Str' "2015" ) ]-@--}-dataFromRows ::-  [Format]-  -- ^ An optional list of formatting instructions for the rows.-  ---  --   Simple numbers and strings do not normally need formatting, but it is-  --   good practice to explicitly declare date-time formats as handling of-  --   these values can vary between different viewers (e.g. browsers).-  ---  --   See the-  --   <https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>-  --   for more details.-  -> [DataRow]-  -- ^ The rows to add. This is expected to be created with one or more-  --   calls to 'dataRow'.-  -> Data-dataFromRows fmts rows =-  let kvs = ("values", toJSON rows)-            : if null fmts-              then []-              else [("format", object (concatMap formatProperty fmts))]-  in (VLData, object kvs)---{-|--Declare data from a named source. The source may be from named 'datasets' within-a specification or a named data source created via the-<https://vega.github.io/vega/docs/api/view/#data Vega View API>.-An optional list of field formatting instructions can be provided as the second-parameter or an empty list to use the default formatting. See the-<https://vega.github.io/vega-lite/docs/data.html#named Vega-Lite documentation>-for details.--@-'toVegaLite'-    [ 'datasets' [ ( "myData", dvals [] ),  ( "myJson", 'dataFromJson' json [] ) ]-    , 'dataFromSource' "myData" []-    , 'mark' 'Bar' []-    , ...-    ]-@--}-dataFromSource :: T.Text -> [Format] -> Data-dataFromSource sourceName fmts =-  let kvs = ("name" .= sourceName)-            : if null fmts-              then []-              else [("format", object (concatMap formatProperty fmts))]-  in (VLData, object kvs)---{-|--Declare data source from a url. The url can be a local path on a web server-or an external http(s) url. Used to create a data ( property, specification ) pair.-An optional list of field formatting instructions can be provided as the second-parameter or an empty list to use the default formatting. See the-<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>-for details.--@-'dataFromUrl' "data/weather.csv" [ 'Parse' [ ( "date", 'FoDate' "%Y-%m-%d %H:%M" ) ] ]-@--}--- TODO: should this use a URL type?-dataFromUrl :: T.Text -> [Format] -> Data-dataFromUrl url fmts =-  let kvs = ("url" .= url)-            : if null fmts-              then []-              else [("format", object (concatMap formatProperty fmts))]-  in (VLData, object kvs)----- | Type of visual mark used to represent data in the visualization.------   The properties of the mark can be changed with the 'MarkProperty'---   constructors - such as 'MHeight' and 'MWidth' -  although not all---   properties apply to all marks.----data Mark-    = Area-      -- ^ An [area mark](https://vega.github.io/vega-lite/docs/area.html)-      --   for representing a series of data elements, such as in a stacked-      --   area chart or streamgraph.-    | Bar-      -- ^ [Bar mark](https://vega.github.io/vega-lite/docs/bar.html)-      --   for histograms, bar charts etc.-    | Boxplot-      -- ^ [Boxplot composite mark](https://vega.github.io/vega-lite/docs/boxplot.html)-      --   for showing summaries of statistical distributions.-      ---      --   Tick marks can be added using 'MTicks' and outliers turned-      --   off with 'MNoOutliers' or configured with 'MOutliers'.-      --   For example:-      ---      --   @-      --   'mark' Boxplot-      --       [ 'MTicks' [ 'MColor' \"black\", 'MSize' 8 ]-      --       , 'MBox' [ 'MFill' \"grey\" ]-      --       , 'MOutliers' [ 'MColor' \"firebrick\" ]-      --   ]-      --   @-      ---      --   The range of the box plot is controlled with 'MExtent' with-      --   the 'IqrScale' or 'ExRange' options (the default is-      --   @IqrScale 1.5@).-      ---      --   @since 0.4.0.0-    | Circle-      -- ^ [Circle mark](https://vega.github.io/vega-lite/docs/circle.html)-      --   for representing points.-    | ErrorBar-      -- ^ [Errorbar composite mark](https://vega.github.io/vega-lite/docs/errorbar.html)-      --   for showing summaries of variation along a signal. By default-      --   no ticks are drawn. To add ticks with default properties use-      --   @`MTicks` []@, otherwise supply a list of configuration options:-      ---      --   @-      --   'mark' ErrorBar [ 'MTicks' [ 'MColor' \"black\", 'MSize' 8 ] ]-      --   @-      ---      --   @since 0.4.0.0-    | ErrorBand-      -- ^ [Errorband composite mark](https://vega.github.io/vega-lite/docs/errorband.html)-      --   for showing summaries of variation along a signal. By default-      --   no border is drawn. To add a border with default properties use-      --   @'MBorders' []@, otherwise supply a list of configuration options:-      ---      --   @-      --   'mark' ErrorBand [ 'MBorders' [ 'MColor' \"black\", 'MStrokeWidth' 0.5 ] ]-      --   @-      ---      --   @since 0.4.0.0-    | Geoshape-      -- ^ [Geoshape](https://vega.github.io/vega-lite/docs/geoshape.html)-      --   determined by geographically referenced coordinates.-    | Line-      -- ^ [Line mark](https://vega.github.io/vega-lite/docs/line.html)-      --   for symbolising a sequence of values.-    | Point-      -- ^ [Point mark](https://vega.github.io/vega-lite/docs/point.html)-      --   for symbolising a data point with a symbol.-    | Rect-      -- ^ [Rectangle mark](https://vega.github.io/vega-lite/docs/rect.html).-    | Rule-      -- ^ [Rule line](https://vega.github.io/vega-lite/docs/rule.html)-      --   connecting two vertices.-    | Square-      -- ^ [Square mark](https://vega.github.io/vega-lite/docs/square.html)-      --   for symbolising points.-    | Text-      -- ^ [Text mark](https://vega.github.io/vega-lite/docs/text.html)-      --   to be displayed at some point location.-    | Tick-      -- ^ Short line - [tick](https://vega.github.io/vega-lite/docs/tick.html) --      --   mark for symbolising point locations.-    | Trail-      -- ^ [Trail mark](https://vega.github.io/vega-lite/docs/trail.html)-      --   (line with variable width along its length).-      ---      --   @since 0.4.0.0---markLabel :: Mark -> T.Text-markLabel Area = "area"-markLabel Bar = "bar"-markLabel Boxplot = "boxplot"-markLabel Circle = "circle"-markLabel ErrorBar = "errorbar"-markLabel ErrorBand = "errorband"-markLabel Line = "line"-markLabel Geoshape = "geoshape"-markLabel Point = "point"-markLabel Rect = "rect"-markLabel Rule = "rule"-markLabel Square = "square"-markLabel Text = "text"-markLabel Tick = "tick"-markLabel Trail = "trail"---{-|--Create a mark specification. All marks must have a type (first parameter) and-can optionally be customised with a list of mark properties such as interpolation-style for lines. To keep the default style for the mark, just provide an empty list-for the second parameter.--@-'mark' 'Circle' []-'mark' 'Line' ['MInterpolate' 'StepAfter']-@--@-let dvals = 'dataFromUrl' \"city.json\" ['TopojsonFeature' \"boroughs\"] []-    markOpts = 'mark' 'Geoshape' ['MFill' \"lightgrey\", 'MStroke' \"white\"]-in 'toVegaLite' [dvals, markOpts]-@--}-mark :: Mark -> [MarkProperty] -> PropertySpec-mark mrk props =-  let jsName = toJSON (markLabel mrk)-      vals = if null props-             then jsName-             else object (("type" .= jsName) : map markProperty props)--  in (VLMark, vals)---{-|--Mark channel properties used for creating a mark channel encoding.--}---- https://vega.github.io/vega-lite/docs/encoding.html#mark-prop--data MarkChannel-    = MName T.Text-      -- ^ Field used for encoding with a mark property channel.-    | MRepeat Arrangement-      -- ^ Reference in a mark channel to a field name generated by 'repeatFlow'-      --   or 'repeat'. The parameter identifies whether reference is being made to-      --   fields that are to be arranged in columns, in rows, or a with a flow layout.-    | MmType Measurement-      -- ^ Level of measurement when encoding with a mark property channel.-    | MScale [ScaleProperty]-      -- ^ Scaling applied to a field when encoding with a mark property channel.-      --   The scale will transform a field's value into a color, shape, size etc.-      ---      --   Use an empty list to remove the scale.-    | MBin [BinProperty]-      -- ^ Discretize numeric values into bins when encoding with a mark property channel.-    | MBinned-      -- ^ Indicate that data encoding with a mark are already binned.-      ---      --   @since 0.4.0.0-    | MSort [SortProperty]-      -- ^ Sort order.-      ---      --   @since 0.4.0.0-    | MTimeUnit TimeUnit-      -- ^ Time unit aggregation of field values when encoding with a mark property channel.-    | MTitle T.Text-      -- ^ Title of a field when encoding with a mark property channel.-      ---      --   @since 0.4.0.0-    | MNoTitle-      -- ^ Draw no title.-      ---      --   @since 0.4.0.0-    | MAggregate Operation-      -- ^ Compute aggregate summary statistics for a field to be encoded with a-      --   mark property channel.-    | MLegend [LegendProperty]-      -- ^ Properties of a legend that describes a mark's encoding.-      ---      --   For no legend, provide an empty list.-    | MSelectionCondition BooleanOp [MarkChannel] [MarkChannel]-      -- ^ Make a mark channel conditional on interactive selection. The first parameter-      --   is a selection condition to evaluate; the second the encoding to apply if that-      --   selection is true; the third parameter is the encoding if the selection is false.-      ---      -- @-      -- 'color'-      --   [ MSelectionCondition ('SelectionName' \"myBrush\")-      --      [ 'MName' \"myField\", 'MmType' 'Ordinal' ]-      --      [ 'MString' \"grey\" ]-      --   ]-      -- @-    | MDataCondition [(BooleanOp, [MarkChannel])] [MarkChannel]-      -- ^ Make a text channel conditional on one or more predicate expressions. The first-      --   parameter is a list of tuples each pairing an expression to evaluate with the encoding-      --   if that expression is @True@. The second is the encoding if none of the expressions-      --   evaluate as @True@.-      ---      -- @-      -- 'color'-      --   [ MDataCondition [ ( 'Expr' \"datum.myField === null\", [ 'MString' \"grey\" ] ) ]-      --      [ MString \"black\" ]-      --   ]-      -- @-      ---      --   The arguments to this constructor have changed in @0.4.0.0@-      --   to support multiple expressions.-    | MPath T.Text-      -- ^ SVG path string used when encoding with a mark property channel. Useful-      --   for providing custom shapes.-    | MNumber Double-      -- ^ Literal numeric value when encoding with a mark property channel.-    | MString T.Text-      -- ^ Literal string value when encoding with a mark property channel.-    | MBoolean Bool-      -- ^ Boolean value when encoding with a mark property channel.--markChannelProperty :: MarkChannel -> [LabelledSpec]-markChannelProperty (MName s) = [field_ s]-markChannelProperty (MRepeat arr) = ["field" .= object [repeat_ arr]]-markChannelProperty (MmType t) = [mtype_ t]-markChannelProperty (MScale sps) = [scaleProp_ sps]-markChannelProperty (MLegend lps) = [legendProp_ lps]-markChannelProperty (MBin bps) = [bin bps]-markChannelProperty MBinned = [binned_]-markChannelProperty (MSort ops) = [sort_ ops]-markChannelProperty (MSelectionCondition selName ifClause elseClause) =-  selCond_ markChannelProperty selName ifClause elseClause-markChannelProperty (MDataCondition tests elseClause) =-  dataCond_ markChannelProperty tests elseClause-markChannelProperty (MTimeUnit tu) = [timeUnit_ tu]-markChannelProperty (MAggregate op) = [aggregate_ op]-markChannelProperty (MPath s) = ["value" .= s]-markChannelProperty (MNumber x) = ["value" .= x]-markChannelProperty (MString s) = ["value" .= s]-markChannelProperty (MBoolean b) = ["value" .= b]-markChannelProperty (MTitle s) = ["title" .= s]-markChannelProperty MNoTitle = ["title" .= A.Null]---{-|--Appearance of a line marker that is overlaid on an area mark.-For use with 'MLine'.--@since 0.4.0.0---}--data LineMarker-  = LMNone-    -- ^ No line marker.-  | LMMarker [MarkProperty]-    -- ^ The properties of a line marker overlain on an area mark.-    ---    --   Use an empty list to use a filled point with default properties.----- An empty object has the same meaning as true, so there is no real need to--- treat 'LMMarker []' specially, but I don't think it complicates things--- here.----lineMarkerSpec :: LineMarker -> VLSpec-lineMarkerSpec LMNone = toJSON False-lineMarkerSpec (LMMarker []) = toJSON True-lineMarkerSpec (LMMarker mps) = object (map markProperty mps)---{-|--Properties for customising the appearance of a mark. For details see the-<https://vega.github.io/vega-lite/docs/mark.html#config Vega-Lite documentation>.--Not all properties are valid for each mark type.--The Vega-Lite specification supports setting those properties that take-@['MarkProperty']@ also to a boolean value. This is currently not-supported in @hvega@.---}---- based on schema 3.3.0 #/definitions/MarkConfig------ but it also contains a number of other properties--data MarkProperty-    = MAlign HAlign-      -- ^ Horizontal alignment of a text mark.-    | MAngle Angle-      -- ^ Rotation angle of a text mark.-    | MBandSize Double-      -- ^ Band size of a bar mark.-    | MBaseline VAlign-      -- ^ Vertical alignment of a text mark.-    | MBinSpacing Double-      -- ^ Offset between bars for a binned field using a bar mark.-      ---      --   The ideal value for this is either @0@ (preferred by statisticians)-      --   or @1@ (the Vega-Lite default value, D3 example style).-    | MBorders [MarkProperty]-      -- ^ Border properties for an 'ErrorBand' mark.-      ---      --   @since 0.4.0.0-    | MBox [MarkProperty]-      -- ^ Box-symbol properties for a 'Boxplot' mark.-      ---      --   @since 0.4.0.0-    | MClip Bool-      -- ^ Should a mark be clipped to the enclosing group's dimensions.-    | MColor Color-      -- ^ Default color of a mark. Note that 'MFill' and 'MStroke' have higher-      --   precedence and will override this if specified.-    | MCursor Cursor-      -- ^ Cursor to be associated with a hyperlink mark.-    | MContinuousBandSize Double-      -- ^ Continuous band size of a bar mark.-    | MDiscreteBandSize Double-      -- ^ Discrete band size of a bar mark.-    | MdX Double-      -- ^ Horizontal offset between a text mark and its anchor.-    | MdY Double-      -- ^ Vertical offset between a text mark and its anchor.-    | MExtent MarkErrorExtent-      -- ^ Extent of whiskers used with 'Boxplot', 'ErrorBar', and-      --   'ErrorBand' marks.-      ---      --   @since 0.4.0.0-    | MFill T.Text-      -- ^ Default fill color of a mark.-    | MFilled Bool-      -- ^ Should a mark's color should be used as the fill color instead of-      --   stroke color.-    | MFillOpacity Opacity-      -- ^ Fill opacity of a mark.-    | MFont T.Text-      -- ^ Font of a text mark. Can be any font name made accessible via-      -- a css file (or a generic font like \"serif\", \"monospace\" etc.).-    | MFontSize Double-      -- ^ Font size, in pixels, used by a text mark.-    | MFontStyle T.Text-      -- ^ Font style (e.g. \"italic\") used by a text mark.-    | MFontWeight FontWeight-      -- ^ Font weight used by a text mark.-    | MHeight Double-      -- ^ Explicitly set the height of a mark. See also 'MWidth'.-      ---      --   @since 0.4.0.0-    | MHRef T.Text-      -- ^ Hyperlink to be associated with a mark making it a clickable-      --   hyperlink.-      ---      --   @since 0.4.0.0-    | MInterpolate MarkInterpolation-      -- ^ Interpolation method used by line and area marks.-    | MLine LineMarker-      -- ^ How should the vertices of an area mark be joined?-      ---      --   @since 0.4.0.0-    | MMedian [MarkProperty]-      -- ^ Median-line properties for the 'Boxplot' mark.-      ---      --   @since 0.4.0.0-    | MOpacity Opacity-      -- ^ Overall opacity of a mark in the range 0 to 1.-    | MOrder Bool-      -- ^ Ordering of vertices in a line or area mark. If @True@ (the default),-      --   the order is determined by measurement type or order channel. If-      --   @False@, the original data order is used.-      ---      --   @since 0.4.0.0-    | MOrient Orientation-      -- ^ Orientation of a non-stacked bar, tick, area or line mark.-    | MOutliers [MarkProperty]-      -- ^ Outlier symbol properties for the 'Boxplot' mark.-      ---      --   @since 0.4.0.0-    | MNoOutliers-      -- ^ Do not draw outliers with the 'Boxplot' mark.-      ---      --   @since 0.4.0.0-    | MPoint PointMarker-      -- ^ Appearance of a point marker joining the vertices of a line or area mark.-      ---      --   @since 0.4.0.0-    | MRadius Double-      -- ^ Polar coordinate radial offset of a text mark from its origin.-    | MRule [MarkProperty]-      -- ^ Rule (main line) properties for the 'ErrorBar' and 'Boxplot' marks.-      ---      --   @since 0.4.0.0-    | MShape Symbol-      -- ^ Shape of a point mark.-    | MShortTimeLabels Bool-      -- ^ Aremonth and weekday names are abbreviated in a text mark?-    | MSize Double-      -- ^ Size of a mark.-    | MStroke T.Text-      -- ^ Default stroke color of a mark.-    | MStrokeCap StrokeCap-      -- ^ Cap style of a mark's stroke.-      ---      --   @since 0.4.0.0-    | MStrokeDash [Double]-      -- ^ The stroke dash style used by a mark, defined by an alternating 'on-off'-      --   sequence of line lengths, in pixels.-    | MStrokeDashOffset Double-      -- ^ The number of pixels before the first line dash is drawn.-    | MStrokeJoin StrokeJoin-      -- ^ Line segment join style of a mark's stroke.-      ---      --   @since 0.4.0.0-    | MStrokeMiterLimit Double-      -- ^ Mitre limit at which to bevel a join between line segments of a-      --   mark's stroke.-      ---      --   @since 0.4.0.0-    | MStrokeOpacity Opacity-      -- ^ Stroke opacity of a mark in the range 0 to 1.-    | MStrokeWidth Double-      -- ^ Stroke width of a mark in pixels.-    | MStyle [T.Text]-      -- ^ Names of custom styles to apply to a mark. Each should refer to a named style-      --   defined in a separate style configuration.-    | MTension Double-      -- ^ Interpolation tension used when interpolating line and area marks.-    | MText T.Text-      -- ^ Placeholder text for a text mark for when a text channel is not specified.-    | MTheta Double-      -- ^ Polar coordinate angle (clockwise from north in radians)-      --   of a text mark from the origin (determined by its-      --   x and y properties).-    | MThickness Double-      -- ^ Thickness of a tick mark.-    | MTicks [MarkProperty]-      -- ^ Tick properties for the 'ErrorBar' or 'Boxplot' mark.-      ---      --   @since 0.4.0.0-    | MTooltip TooltipContent-      -- ^ The tooltip content for a mark.-      ---      --   @since 0.4.0.0-    | MWidth Double-      -- ^ Explicitly set the width of a mark (e.g. the bar width). See also-      --   'MHeight'.-      ---      --   @since 0.4.0.0-    | MX Double-      -- ^ X position of a mark.-      ---      --   @since 0.4.0.0-    | MX2 Double-      -- ^ X2 position of a mark. This is the secondary position for-      --   lines and area marks).-      ---      --   @since 0.4.0.0-    | MXOffset Double-      -- ^ X position offset of a mark.-      ---      --   @since 0.4.0.0-    | MX2Offset Double-      -- ^ X2 position offset of a mark.-      ---      --   @since 0.4.0.0-    | MY Double-      -- ^ Y position of a mark.-      ---      --   @since 0.4.0.0-    | MY2 Double-      -- ^ Y2 position of a mark. This is the secondary position for-      --   lines and area marks).-      ---      --   @since 0.4.0.0-    | MYOffset Double-      -- ^ Y position offset of a mark.-      ---      --   @since 0.4.0.0-    | MY2Offset Double-      -- ^ Y2 position offset of a mark.-      ---      --   @since 0.4.0.0----markProperty :: MarkProperty -> LabelledSpec-markProperty (MFilled b) = "filled" .= b-markProperty (MBorders mps) = mprops_ "borders" mps-markProperty (MBox mps) = mprops_ "box" mps-markProperty (MClip b) = "clip" .= b-markProperty (MColor col) = "color" .= col-markProperty (MCursor cur) = "cursor" .= cursorLabel cur-markProperty (MFill col) = "fill" .= col-markProperty (MHeight x) = "height" .= x-markProperty (MStroke t) = "stroke" .= t-markProperty (MStrokeCap sc) = "strokeCap" .= strokeCapLabel sc-markProperty (MStrokeOpacity x) = "strokeOpacity" .= x-markProperty (MStrokeWidth w) = "strokeWidth" .= w-markProperty (MStrokeDash xs) = "strokeDash" .= xs-markProperty (MStrokeDashOffset x) = "strokeDashOffset" .= x-markProperty (MStrokeJoin sj) = "strokeJoin" .= strokeJoinLabel sj-markProperty (MStrokeMiterLimit x) = "strokeMiterLimit" .= x-markProperty (MMedian mps) = mprops_ "median" mps-markProperty (MOpacity x) = "opacity" .= x-markProperty (MFillOpacity x) = "fillOpacity" .= x-markProperty (MStyle [style]) = "style" .= style  -- special case singleton-markProperty (MStyle styles) = "style" .= styles-markProperty (MInterpolate interp) = "interpolate" .= markInterpolationLabel interp-markProperty (MLine lm) = "line" .= lineMarkerSpec lm-markProperty (MTension x) = "tension" .= x-markProperty (MOrder b) = "order" .= b-markProperty (MOrient orient) = "orient" .= orientationSpec orient-markProperty (MOutliers []) = "outliers" .= True  -- TODO: should mprops_ do this?-markProperty (MOutliers mps) = mprops_ "outliers" mps-markProperty MNoOutliers = "outliers" .= False-markProperty (MPoint pm) = "point" .= pointMarkerSpec pm-markProperty (MShape sym) = "shape" .= symbolLabel sym-markProperty (MSize x) = "size" .= x-markProperty (MAngle x) = "angle" .= x-markProperty (MAlign algn) = "align" .= hAlignLabel algn-markProperty (MBaseline va) = "baseline" .= vAlignLabel va-markProperty (MdX dx) = "dx" .= dx-markProperty (MdY dy) = "dy" .= dy-markProperty (MExtent mee) = markErrorExtentLSpec mee-markProperty (MFont fnt) = "font" .= fnt-markProperty (MFontSize x) = "fontSize" .= x-markProperty (MFontStyle fSty) = "fontStyle" .= fSty-markProperty (MFontWeight w) = "fontWeight" .= fontWeightSpec w-markProperty (MHRef s) = "href" .= s-markProperty (MRadius x) = "radius" .= x-markProperty (MRule mps) = mprops_ "rule" mps-markProperty (MText txt) = "text" .= txt-markProperty (MTheta x) = "theta" .= x-markProperty (MTicks mps) = mprops_ "ticks" mps-markProperty (MBinSpacing x) = "binSpacing" .= x-markProperty (MContinuousBandSize x) = "continuousBandSize" .= x-markProperty (MDiscreteBandSize x) = "discreteBandSize" .= x-markProperty (MShortTimeLabels b) = "shortTimeLabels" .= b-markProperty (MBandSize x) = "bandSize" .= x-markProperty (MThickness x) = "thickness" .= x-markProperty (MTooltip TTNone) = "tooltip" .= A.Null-markProperty (MTooltip tc) = "tooltip" .= object ["content" .= ttContentLabel tc]-markProperty (MWidth x) = "width" .= x-markProperty (MX x) = "x" .= x-markProperty (MY x) = "y" .= x-markProperty (MX2 x) = "x2" .= x-markProperty (MY2 x) = "y2" .= x-markProperty (MXOffset x) = "xOffset" .= x-markProperty (MYOffset x) = "yOffset" .= x-markProperty (MX2Offset x) = "x2Offset" .= x-markProperty (MY2Offset x) = "y2Offset" .= x----- | How are strokes capped? This is used with 'MStrokeCap', 'VBStrokeCap',---   and `ViewStrokeCap'.------   @since 0.4.0.0--data StrokeCap-    = CButt-      -- ^ Butt stroke cap.-    | CRound-      -- ^ Rounded stroke cap.-    | CSquare-      -- ^ Square stroke cap.---strokeCapLabel :: StrokeCap -> T.Text-strokeCapLabel CButt = "butt"-strokeCapLabel CRound = "round"-strokeCapLabel CSquare = "square"----- | How are strokes joined? This is used with 'MStrokeJoin', 'VBStrokeJoin',---   and `ViewStrokeJoin'.---------   @since 0.4.0.0--data StrokeJoin-    = JMiter-      -- ^ Mitred stroke join.-    | JRound-      -- ^ Rounded stroke join.-    | JBevel-      -- ^ Bevelled stroke join.---strokeJoinLabel :: StrokeJoin -> T.Text-strokeJoinLabel JMiter = "miter"-strokeJoinLabel JRound = "round"-strokeJoinLabel JBevel = "bevel"---{-|--Create an encoding specification from a list of channel encodings,-such as 'position', 'color', 'size', 'shape'.--@-enc = 'encoding'-        . 'position' 'X' [ 'PName' \"Animal\", 'PmType' 'Ordinal' ]-        . 'position' 'Y' [ PName \"Age\", 'PmType' 'Quantitative' ]-        . 'shape' [ 'MName' \"Species\", 'MmType' 'Nominal' ]-        . 'size' [ 'MName' \"Population\", 'MmType' 'Quantitative' ]-@--The type of @enc@ in this example is @[LabelledSpec] -> PropertySpec@,-so it can either be used to add further encoding specifications or as-@enc []@ to create a specification.---}-encoding :: [LabelledSpec] -> PropertySpec-encoding channels = (VLEncoding, object channels)---- TODO:------  encoding of X2/... shouldn't include the PmType in the output, apparently---  so we could try and filter that out, or just rely on the user to not---  add the PmType fields in this case.--{-|--Type of position channel, @X@ and @Y@ represent horizontal and vertical axis-dimensions on a plane and @X2@ and @Y2@ represent secondary axis dimensions where-two scales are overlaid in the same space. Geographic positions represented by-longitude and latiutude values are identified with @Longitude@, @Latitude@ and-their respective secondary equivalents. Such geographic position channels are-subject to a map projection (set using 'projection') before being placed graphically.---}-data Position-    = X-    | Y-    | X2-    -- ^ The secondary coordinate for ranged 'Area', 'Bar', 'Rect', and 'Rule'-    --    marks.-    | Y2-    -- ^ The secondary coordinate for ranged 'Area', 'Bar', 'Rect', and 'Rule'-    --    marks.-    | XError-      -- ^ Indicates that the 'X' channel represents the mid-point and-      --   the 'XError' channel gives the offset. If 'XError2' is not-      --   defined then this channel value is applied symmetrically.-      ---      --   @since 0.4.0.0-    | XError2-      -- ^ Used to support asymmetric error ranges defined as 'XError'-      --   and 'XError2'. One of 'XError' or 'XError2' channels must-      --   contain positive values and the other negative values.-      ---      --   @since 0.4.0.0-    | YError-      -- ^ Indicates that the 'Y' channel represents the mid-point and-      --   the 'YError' channel gives the offset. If 'YError2' is not-      --   defined then this channel value is applied symmetrically.-      ---      --   @since 0.4.0.0-    | YError2-      -- ^ Used to support asymmetric error ranges defined as 'YError'-      --   and 'YError2'. One of 'YError' or 'YError2' channels must-      --   contain positive values and the other negative values.-      ---      --   @since 0.4.0.0-    | Longitude-      -- ^ The longitude value for projections.-    | Latitude-      -- ^ The latitude value for projections.-    | Longitude2-      -- ^ A second longitude coordinate.-    | Latitude2-      -- ^ A second longitude coordinate.---{-|--Type of measurement to be associated with some channel.---}--data Measurement-    = Nominal-      -- ^ Data are categories identified by name alone and which have no intrinsic order.-    | Ordinal-      -- ^ Data are also categories, but ones which have some natural order.-    | Quantitative-      -- ^ Data are numeric measurements typically on a continuous scale.-    | Temporal-      -- ^ Data represents time in some manner.-    | GeoFeature-      -- ^ Geospatial position encoding ('Longitude' and 'Latitude') should specify the 'PmType'-      -- as @Quantitative@. Geographically referenced features encoded as 'shape' marks-      -- should specify 'MmType' as @GeoFeature@ (Vega-Lite currently refers to this type-      -- as @<https://vega.github.io/vega-lite/docs/encoding.html geojson>@.---{-|--Type of binning property to customise. See the-<https://vega.github.io/vega-lite/docs/bin.html Vega-Lite documentation> for-more details.--This is used with: 'binAs', 'DBin', 'FBin', 'HBin', 'MBin', 'OBin',-'PBin', and 'TBin'.---}---- based on schema 3.3.0 #/definitions/BinParams--data BinProperty-    = AlreadyBinned Bool-      -- ^ Should the input data be treated as already binned?-      ---      --   @since 0.4.0.0-    | BinAnchor Double-      -- ^ A value in the binned domain at which to anchor the bins, shifting the bin-      --   boundaries if necessary to ensure that a boundary aligns with the anchor-      --   value.-      ---      --   @since 0.4.0.0-    | Base Double-      -- ^ The number base to use for automatic bin determination.-      ---      --   Default is @10@.-    | Divide [Double]-      -- ^ Scale factors indicating allowable subdivisions.-      ---      --   Default is @[5, 2]@.-      ---      --   Prior to @0.4.0.0@ the @Divide@ constructor took two numbers.-    | Extent Double Double-      -- ^ The range (minimum, maximum) of the desired bin values.-    | MaxBins Int-      -- ^ The maxium number of bins.-      ---      --   Default is @6@ for 'row', 'column', and 'shape' channels,-      --   @10@ otherwise.-    | MinStep Double-      -- ^ A minimum allowable step size.-    | Nice Bool-      -- ^ If @True@, the bin boundaries are adjusted to use human-friendly values,-      --   such as multiples of ten.-      ---      --   Default is @True@.-    | Step Double-      -- ^ The step size to use between bins.-      ---      --   If specified, 'MaxBins' and other related options are ignored.-    | Steps [Double]-      -- ^ Pick the step size from this list.---binProperty :: BinProperty -> LabelledSpec-binProperty (AlreadyBinned b) = "binned" .= b-binProperty (BinAnchor x) = "anchor" .= x-binProperty (Base x) = "base" .= x-binProperty (Divide xs) = "divide" .= xs-binProperty (Extent mn mx) = "extent" .= [ mn, mx ]-binProperty (MaxBins n) = "maxbins" .= n-binProperty (MinStep x) = "minstep" .= x-binProperty (Nice b) = "nice" .= b-binProperty (Step x) = "step" .= x-binProperty (Steps xs) = "steps" .= xs---bin :: [BinProperty] -> LabelledSpec-bin [] = "bin" .= True-bin xs = "bin" .= object (map binProperty xs)--binned_ :: LabelledSpec-binned_ = "bin" .= fromT "binned"---{-|--Type of aggregation operation. See the-<https://vega.github.io/vega-lite/docs/aggregate.html#ops Vega-Lite documentation>-for more details.--The @Average@ constructor was removed in version @0.4.0.0@; use 'Mean' instead.---}-data Operation-    = ArgMax (Maybe T.Text)-      -- ^ An input data object containing the maximum field value to be used-      --   in an aggregation operation.-      ---      --   If supplied as part of an encoding aggregation, the parameter-      --   should be 'Just' the name of the field to maximise. When used-      --   as part of a transform the parameter should be 'Nothing' as the-      --   field is specified in the 'aggregate' call.-      ---      --   Encoding example, to find the production budget for the maximum-      --   US grossing film in each genre:-      ---      --   @-      --   'encoding'-      --     . 'position' 'X'-      --                [ 'PName' \"Production_Budget\"-      --                , 'PmType' 'Quantitative'-      --                , 'PAggregate' ('ArgMax' ('Just' \"US_Gross\"))-      --                ]-      --     . 'position' 'Y' ['PName' \"Major_Genre\", 'PmType' 'Nominal']-      --   @-      ---      --   An example of its use as part of an 'aggregate' call:-      ---      --   @-      --   'transform'-      --     . 'aggregate'-      --         [ 'opAs' ('ArgMax' 'Nothing') \"US_Gross\" \"amUSGross\"]-      --         [\"Major_Genre\"]-      --   @-      ---      --   The optional field name was added in the @0.4.0.0@ release.-    | ArgMin (Maybe T.Text)-      -- ^ An input data object containing the minimum field value to be used-      --   in an aggregation operation. See 'ArgMax' for a discussion of the-      --   optional argument.-      ---      --   The optional field name was added in the @0.4.0.0@ release.-    | CI0-      -- ^ Lower 95% confidence interval to be used in an aggregation operation.-    | CI1-      -- ^ Upper 95% confidence interval to be used in an aggregation operation.-    | Count-      -- ^ Total count of data objects to be used in an aggregation operation.-    | Distinct-      -- ^ Count of distinct data objects to be used in an aggregation operation.-    | Max-      -- ^ Maximum field value to be used in an aggregation operation.-    | Mean-      -- ^ Mean field value to be used in an aggregation operation.-    | Median-      -- ^ Median field value to be used in an aggregation operation.-    | Min-      -- ^ 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.-    | Q1-      -- ^ Lower quartile boundary of field values to be used in an aggregation operation.-    | Q3-      -- ^ Upper quartile boundary of field values to be used in an aggregation operation.-    | Stderr-      -- ^ Standard error of field values to be used in an aggregate operation.-    | Stdev-      -- ^ Sample standard deviation of field values to be used in an aggregate operation.-    | StdevP-      -- ^ Population standard deviation of field values to be used in an aggregate operation.-    | Sum-      -- ^ Sum of field values to be used in an aggregate operation.-    | Valid-      -- ^ Count of values that are not @null@, @undefined@, or @NaN@ to be used in an-      -- aggregation operation.-    | Variance-      -- ^ Sample variance of field values to be used in an aggregate operation.-    | VarianceP-      -- ^ Population variance of field values to be used in an aggregate operation.----- Unlike Elm, not checking if the string is empty for ArgMin/Max--operationSpec :: Operation -> VLSpec-operationSpec (ArgMax Nothing) = "argmax"-operationSpec (ArgMax (Just s)) = object ["argmax" .= s]-operationSpec (ArgMin Nothing) = "argmin"-operationSpec (ArgMin (Just s)) = object ["argmin" .= s]-operationSpec CI0 = "ci0"-operationSpec CI1 = "ci1"-operationSpec Count = "count"-operationSpec Distinct = "distinct"-operationSpec Max = "max"-operationSpec Mean = "mean"-operationSpec Median = "median"-operationSpec Min = "min"-operationSpec Missing = "missing"-operationSpec Q1 = "q1"-operationSpec Q3 = "q3"-operationSpec Stderr = "stderr"-operationSpec Stdev = "stdev"-operationSpec StdevP = "stdevp"-operationSpec Sum = "sum"-operationSpec Valid = "valid"-operationSpec Variance = "variance"-operationSpec VarianceP = "variancep"----- | Identifies how repeated or faceted views are arranged.------   This is used with a number of constructors: 'ByRepeatOp',---   'HRepeat', 'MRepeat', 'ORepeat', 'PRepeat', and 'TRepeat'.---- based on schema 3.3.0 #/definitions/RepeatRef--data Arrangement-    = Column-      -- ^ Column arrangement.-    | Row-      -- ^ Row arrangement.-    | Flow-      -- ^ Flow arrangement (aka \"repeat\").-      ---      --   @since 0.4.0.0---arrangementLabel :: Arrangement -> T.Text-arrangementLabel Column = "column"-arrangementLabel Row = "row"-arrangementLabel Flow = "repeat"  -- NOTE: not "flow"!----- | How are stacks applied within a transform?------   Prior to version @0.4.0.0@ the @StackProperty@ type was---   what is now @StackOffset@.--data StackProperty-    = StOffset StackOffset-      -- ^ Stack offset.-      ---      --   @since 0.4.0.0-    | StSort [SortField]-      -- ^ Ordering within a stack.-      ---      --   @since 0.4.0.0----- | Describes the type of stacking to apply to a bar chart.------   In @0.4.0.0@ this was renamed from @StackProperty@ to @StackOffset@,---   but the constructor names have not changed.----data StackOffset-    = StZero-      -- ^ Offset a stacked layout using a baseline at the foot of-      --   the stack.-    | StNormalize-      -- ^ Rescale a stacked layout to use a common height while-      --   preserving the relative size of stacked quantities.-    | StCenter-      -- ^ Offset a stacked layout using a central stack baseline.-    | NoStack-      -- ^ Do not stack marks, but create a layered plot.--stackOffsetSpec :: StackOffset -> VLSpec-stackOffsetSpec StZero = "zero"-stackOffsetSpec StNormalize = "normalize"-stackOffsetSpec StCenter = "center"-stackOffsetSpec NoStack = A.Null--stackOffset :: StackOffset -> LabelledSpec-stackOffset so = "stack" .= stackOffsetSpec so---stackPropertySpecOffset , stackPropertySpecSort:: StackProperty -> Maybe VLSpec-stackPropertySpecOffset (StOffset op) = Just (stackOffsetSpec op)-stackPropertySpecOffset _ = Nothing--stackPropertySpecSort (StSort sfs) = Just (toJSON (map sortFieldSpec sfs))-stackPropertySpecSort _ = Nothing---{-|--Apply a stack transform for positioning multiple values. This is an alternative-to specifying stacking directly when encoding position.--@-'transform'-    . 'aggregate' [ 'opAs' 'Count' \"\" \"count_*\" ] [ \"Origin\", \"Cylinders\" ]-    . 'stack' "count_*"-        []-        \"stack_count_Origin1\"-        \"stack_count_Origin2\"-        [ 'StOffset' 'StNormalize', 'StSort' [ 'WAscending' \"Origin\" ] ]-    . 'window'-        [ ( [ 'WAggregateOp' 'Min', 'WField' \"stack_count_Origin1\" ], \"x\" )-        , ( [ 'WAggregateOp' 'Max', 'WField' \"stack_count_Origin2\" ], \"x2\" )-        ]-        [ 'WFrame' Nothing Nothing, 'WGroupBy' [ \"Origin\" ] ]-    . 'stack' \"count_*\"-        [ \"Origin\" ]-        \"y\"-        \"y2\"-        [ 'StOffset' 'StNormalize', 'StSort' [ 'WAscending' \"Cylinders\" ] ]-@--@since 0.4.0.0---}--stack ::-  T.Text-  -- ^ The field to be stacked.-  -> [T.Text]-  -- ^ The fields to group by.-  -> T.Text-  -- ^ The output field name (start).-  -> T.Text-  -- ^ The output field name (end).-  -> [StackProperty]-  -- ^ Offset and sort properties.-  -> BuildLabelledSpecs-stack f grp start end sProps ols =-  let ags = [ toJSON f, toJSON grp, toJSON start, toJSON end-            , toSpec (mapMaybe stackPropertySpecOffset sProps)-            , toSpec (mapMaybe stackPropertySpecSort sProps)-            ]--      toSpec [x] = x-      toSpec _ = A.Null--  in ("stack", toJSON ags) : ols---{-|--Individual scale property. These are used to customise an individual scale-transformation. To customise all scales use 'configure' and supply relevant-'ScaleConfig' values. For more details see the-<https://vega.github.io/vega-lite/docs/scale.html Vega-Lite documentation>.--There are two utility routines for constructing a list of scale-properties: 'categoricalDomainMap' and 'domainRangeMap'.--The @SReverse@ constructor was removed in version @0.4.0.0@, as it-represented a Vega, rather than Vega-Lite, property. The order of-a scale can be changed with the 'PSort' constructor.--}---- based on schema 3.3.0 #/definitions/Scale--data ScaleProperty-    = SType Scale-      -- ^ Type of scaling to apply.-    | SAlign Double-      -- ^ Alignment of the steps within the scale range. A value of-      --   @0@ shifts the bands to an axis, @1@ away from the axis,-      --   and @0.5@ is centered within the range.-      ---      --   The input is clamped so that values less than 0 are mapped-      --   to 0 and greater than 1 to 1.-      ---      --   @since 0.4.0.0-    | SBase Double-      -- ^ The base to use for log scaling ('ScLog').-      ---      --   Default is @10@.-      ---      --   @since 0.4.0.0-    | SBins [Double]-      -- ^ An array of bin boundaries over the scale domain. If give, axes and legends will use-      --   these boundaries to inform the choice of tick marks and text labels.-      ---      --   @since 0.4.0.0-    | SClamp Bool-      -- ^ Should values outside the data domain be clamped (to the minimum or-      --   maximum value)?-    | SConstant Double-      -- ^ The desired slope of the 'ScSymLog' function at zero.-      ---      --   The default is @1@.-      ---      --   @since 0.4.0.0-    | SDomain ScaleDomain-      -- ^ Custom scaling domain.-    | SExponent Double-      -- ^ The exponent to use for power scaling ('ScPow').-      ---      --   @since 0.4.0.0-    | SInterpolate CInterpolate-      -- ^ Interpolation method for scaling range values.-    | SNice ScaleNice-      -- ^ \"Nice\" minimum and maximum values in a scaling (e.g. multiples of 10).-    | SPadding Double-      -- ^ Padding in pixels to apply to a scaling.-    | SPaddingInner Double-      -- ^ Inner padding to apply to a band scaling.-    | SPaddingOuter Double-      -- ^ Outer padding to apply to a band scaling.-    | SRange ScaleRange-      -- ^ Range of a scaling. The type of range depends on the encoding channel.-    | SRangeStep (Maybe Double)-      -- ^ Distance between the starts of adjacent bands in a band scaling. If-      --   @Nothing@, the distance is determined automatically.-    | SRound Bool-      -- ^ Are numeric values in a scaling are rounded to integers?-      ---      --   The default is @False@.-    | SScheme T.Text [Double]-      -- ^  Color scheme used by a color scaling. The first parameter is the-      --    name of the scheme (e.g. \"viridis\") and the second an optional-      --    specification, which can contain 1, 2, or 3 numbers:-      ---      --      - the number of colors to use (list of one number);-      --      - the extent of the color range to use (list of two numbers between 0 and 1);-      --      - the number of colors and extent (three numbers, first is the number of colors).-      ---      --    The number of colors was broken prior to @0.4.0.0@ and the option to-      --    define both the count and extent was added in @0.4.0.0@.-    | SZero Bool-      -- ^ Should a numeric scaling be forced to include a zero value?-      ---      --   Not all scales support @SZero@ and the default depends on the type of-      --   channel.--scaleProperty :: ScaleProperty -> LabelledSpec-scaleProperty (SType sType) = "type" .= scaleLabel sType-scaleProperty (SAlign c) = "align" .= clamped 0 1 c-scaleProperty (SBase x) = "base" .= x-scaleProperty (SBins xs) = "bins" .= xs-scaleProperty (SClamp b) = "clamp" .= b-scaleProperty (SConstant x) = "constant" .= x-scaleProperty (SDomain sdType) = "domain" .= scaleDomainSpec sdType-scaleProperty (SExponent x) = "exponent" .= x-scaleProperty (SInterpolate interp) = "interpolate" .= cInterpolateSpec interp-scaleProperty (SNice ni) = "nice" .= scaleNiceSpec ni-scaleProperty (SPadding x) = "padding" .= x-scaleProperty (SPaddingInner x) = "paddingInner" .= x-scaleProperty (SPaddingOuter x) = "paddingOuter" .= x-scaleProperty (SRange (RNumbers xs)) = "range" .= xs-scaleProperty (SRange (RStrings ss)) = "range" .= ss-scaleProperty (SRange (RName s)) = "range" .= s-scaleProperty (SRangeStep numOrNull) = "rangeStep" .= maybe A.Null toJSON numOrNull-scaleProperty (SRound b) = "round" .= b-scaleProperty (SScheme nme extent) = schemeProperty nme extent-scaleProperty (SZero b) = "zero" .= b----- TODO: there should probably be a more-structured way to specify this------ based on schema 3.3.0 #/definitions/SchemeParams--schemeProperty :: T.Text -> [Double] -> LabelledSpec-schemeProperty nme [n] = "scheme" .= object ["name" .= nme, "count" .= n]-schemeProperty nme [mn, mx] = "scheme" .= object ["name" .= nme, "extent" .= [mn, mx]]-schemeProperty nme [n, mn, mx] = "scheme" .= object ["name" .= nme, "count" .= n, "extent" .= [mn, mx]]-schemeProperty nme _ = "scheme" .= nme----- | Used to indicate the type of scale transformation to apply.------   The @0.4.0.0@ release removed the @ScSequential@ constructor, as---   'ScLinear' should be used instead.--data Scale-    = ScLinear-      -- ^ A linear scale.-    | ScPow-      -- ^ A power scale. The exponent to use for scaling is specified with-      --   'SExponent'.-    | ScSqrt-      -- ^ A square-root scale.-    | ScLog-      -- ^ A log scale. Defaults to log of base 10, but can be customised with-      --   'SBase'.-    | ScSymLog-      -- ^ A [symmetrical log (PDF link)](https://www.researchgate.net/profile/John_Webber4/publication/233967063_A_bi-symmetric_log_transformation_for_wide-range_data/links/0fcfd50d791c85082e000000.pdf)-      --   scale. Similar to a log scale but supports zero and negative values. The slope-      --   of the function at zero can be set with 'SConstant'.-      ---      --   @since 0.4.0.0-    | ScTime-      -- ^ A temporal scale.-    | ScUtc-      -- ^ A temporal scale, in UTC.-    | ScOrdinal-      -- ^ An ordinal scale.-    | ScBand-      -- ^ A band scale.-    | ScPoint-      -- ^ A point scale.-    | ScBinLinear-      -- ^ A linear band scale.-    | ScBinOrdinal-      -- ^ An ordinal band scale.-    | ScQuantile-      -- ^ A quantile scale.-      ---      --   @since 0.4.0.0-    | ScQuantize-      -- ^ A quantizing scale.-      ---      --   @since 0.4.0.0-    | ScThreshold-      -- ^ A threshold scale.-      ---      --   @since 0.4.0.0---scaleLabel :: Scale -> T.Text-scaleLabel ScLinear = "linear"-scaleLabel ScPow = "pow"-scaleLabel ScSqrt = "sqrt"-scaleLabel ScLog = "log"-scaleLabel ScSymLog = "symlog"-scaleLabel ScTime = "time"-scaleLabel ScUtc = "utc"-scaleLabel ScOrdinal = "ordinal"-scaleLabel ScBand = "band"-scaleLabel ScPoint = "point"-scaleLabel ScBinLinear = "bin-linear"-scaleLabel ScBinOrdinal = "bin-ordinal"-scaleLabel ScQuantile = "quantile"-scaleLabel ScQuantize = "quantize"-scaleLabel ScThreshold = "threshold"---{-|--Describes the scale domain (type of data in scale). For full details see the-<https://vega.github.io/vega-lite/docs/scale.html#domain Vega-Lite documentation>.--}--data ScaleDomain-    = DNumbers [Double]-      -- ^ Numeric values that define a scale domain.-    | DStrings [T.Text]-      -- ^ String values that define a scale domain.-    | DDateTimes [[DateTime]]-      -- ^ Date-time values that define a scale domain.-    | DSelection T.Text-      -- ^ Scale domain based on a named interactive selection.-    | Unaggregated-    -- ^ Specify an unaggregated scale domain (type of data in scale).--scaleDomainSpec :: ScaleDomain -> VLSpec-scaleDomainSpec (DNumbers nums) = toJSON (map toJSON nums)-scaleDomainSpec (DDateTimes dts) = toJSON (map (object . map dateTimeProperty) dts)-scaleDomainSpec (DStrings cats) = toJSON (map toJSON cats)-scaleDomainSpec (DSelection selName) = object ["selection" .= selName]-scaleDomainSpec Unaggregated = "unaggregated"---{-|--Describes the way a scale can be rounded to \"nice\" numbers. For full details see the-<https://vega.github.io/vega-lite/docs/scale.html#continuous Vega-Lite documentation>.--}-data ScaleNice-    = NMillisecond-      -- ^ Nice time intervals that try to align with rounded milliseconds.-    | NSecond-      -- ^ Nice time intervals that try to align with whole or rounded seconds.-    | NMinute-      -- ^ Nice time intervals that try to align with whole or rounded minutes.-    | NHour-      -- ^ Nice time intervals that try to align with whole or rounded hours.-    | NDay-      -- ^ Nice time intervals that try to align with whole or rounded days.-    | NWeek-    -- ^ Nice time intervals that try to align with whole or rounded weeks.-    | NMonth-      -- ^ Nice time intervals that try to align with whole or rounded months.-    | NYear-      -- ^ Nice time intervals that try to align with whole or rounded years.-    | NInterval TimeUnit Int-      -- ^ \"Nice\" temporal interval values when scaling.-    | IsNice Bool-      -- ^ Enable or disable nice scaling.-    | NTickCount Int-      -- ^ Desired number of tick marks in a \"nice\" scaling.---scaleNiceSpec :: ScaleNice -> VLSpec-scaleNiceSpec NMillisecond = fromT "millisecond"-scaleNiceSpec NSecond = fromT "second"-scaleNiceSpec NMinute = fromT "minute"-scaleNiceSpec NHour = fromT "hour"-scaleNiceSpec NDay = fromT "day"-scaleNiceSpec NWeek = fromT "week"-scaleNiceSpec NMonth = fromT "month"-scaleNiceSpec NYear = fromT "year"-scaleNiceSpec (NInterval tu step) =-  object ["interval" .= timeUnitLabel tu, "step" .= step]-scaleNiceSpec (IsNice b) = toJSON b-scaleNiceSpec (NTickCount n) = toJSON n---{-|--Describes a scale range of scale output values. For full details see the-<https://vega.github.io/vega-lite/docs/scale.html#range Vega-Lite documentation>.--For color scales you can also specify a color [scheme](https://vega.github.io/vega-lite/docs/scale.html#scheme)-instead of range.--Any directly specified range for @x@ and @y@ channels will be ignored. Range can be customized-via the view's corresponding [size](https://vega.github.io/vega-lite/docs/size.html)-('width' and 'height') or via range steps and paddings properties (e.g. 'SCRangeStep')-for band and point scales.---}--data ScaleRange-    = RNumbers [Double]-      -- ^ For [continuous scales](https://vega.github.io/vega-lite/docs/scale.html#continuous),-      --   a two-element array indicating minimum and maximum values, or an array with more than-      --   two entries for specifying a-      --   [piecewise scale](https://vega.github.io/vega-lite/docs/scale.html#piecewise).-    | RStrings [T.Text]-      -- ^ Text scale range for discrete scales.-    | RName T.Text-      -- ^ Name of a [pre-defined named scale range](https://vega.github.io/vega-lite/docs/scale.html#range-config)-      --   (e.g. \"symbol\" or \"diverging\").--{-|--Indicates the type of color interpolation to apply, when mapping a data field-onto a color scale.--For details see the-<https://vega.github.io/vega-lite/docs/scale.html#continuous Vega-Lite documentation>.---}-data CInterpolate-    = CubeHelix Double-      -- ^ Cube helix color interpolation for continuous color scales using the given-      --   gamma value (anchored at 1).-    | CubeHelixLong Double-      -- ^ Long-path cube helix color interpolation for continuous color scales using-      --   the given gamma value (anchored at 1).-    | Hcl-      -- ^ HCL color interpolation for continuous color scales.-    | HclLong-      -- ^ HCL color interpolation in polar coordinate space for continuous color scales.-    | Hsl-      -- ^ HSL color interpolation for continuous color scales.-    | HslLong-      -- ^ HSL color interpolation in polar coordinate space for continuous color scales.-    | Lab-      -- ^ Lab color interpolation for continuous color scales.-    | Rgb Double-      -- ^ RGB color interpolation for continuous color scales using the given gamma-      --   value (anchored at 1).----- Need to tie down some types as things are too polymorphic,--- particularly in the presence of OverloadedStrings.----pairT :: T.Text -> T.Text -> (T.Text, Value)-pairT a b = a .= b---cInterpolateSpec :: CInterpolate -> VLSpec-cInterpolateSpec (Rgb gamma) = object [pairT "type" "rgb", "gamma" .= gamma]-cInterpolateSpec Hsl = object [pairT "type" "hsl"]-cInterpolateSpec HslLong = object [pairT "type" "hsl-long"]-cInterpolateSpec Lab = object [pairT "type" "lab"]-cInterpolateSpec Hcl = object [pairT "type" "hcl"]-cInterpolateSpec HclLong = object [pairT "type" "hcl-long"]-cInterpolateSpec (CubeHelix gamma) = object [pairT "type" "cubehelix", "gamma" .= gamma]-cInterpolateSpec (CubeHelixLong gamma) = object [pairT "type" "cubehelix-long", "gamma" .= gamma]---{-|--Allow type of sorting to be customised. For details see the-<https://vega.github.io/vega-lite/docs/sort.html Vega-Lite documentation>.--The constructors have been changed in version @0.4.0.0@, with-@Op@, @ByField@, and @ByRepeat@ removed, and their functionality-replaced with 'ByRepeatOp', 'ByFieldOp', and 'ByChannel'.---}-data SortProperty-    = Ascending-      -- ^ Sorting is from low to high.-    | Descending-      -- ^ Sorting is from high to low.-    | CustomSort DataValues-      -- ^ Custom sort order listing data values explicitly.-      ---      --   @since 0.4.0.0-    | ByRepeatOp Arrangement Operation-      -- ^ Sort by the aggregated summaries of the given fields-      --   (referenced by a repeat iterator) using an aggregation-      --   operation.-      ---      --   @since 0.4.0.0-    | ByFieldOp T.Text Operation-      -- ^ Sort by the aggregated summary of a field using an aggregation-      --   operation. The following example sorts the categorical data field-      --   @variety@ by the mean age of the data in each variety category:-      ---      -- @-      -- 'position' 'Y'-      --   [ 'PName' "variety"-      --   , 'PmType' 'Ordinal'-      --   , 'PSort' [ ByFieldOp "age" 'Mean', 'Descending' ]-      --   ]-      -- @-      ---      --   @since 0.4.0.0-    | ByChannel Channel-      -- ^ Sort by another channel.-      ---      -- @-      -- 'position' 'Y'-      --  [ 'PName' "age"-      --  , 'PmType' 'Ordinal'-      --  , 'PSort' [ ByChannel 'ChX' ]-      --  ]-      -- @-      ---      --   @since 0.4.0.0---sortProperty :: SortProperty -> [LabelledSpec]-sortProperty Ascending = [order_ "ascending"]-sortProperty Descending = [order_ "descending"]-sortProperty (ByChannel ch) = ["encoding" .= channelLabel ch]-sortProperty (ByFieldOp field op) = [field_ field, op_ op]-sortProperty (ByRepeatOp arr op) = ["field" .= object [repeat_ arr], op_ op]-sortProperty (CustomSort _) = []---sortPropertySpec :: [SortProperty] -> VLSpec-sortPropertySpec [] = A.Null-sortPropertySpec [Ascending] = fromT "ascending"-sortPropertySpec [Descending] = fromT "descending"-sortPropertySpec [CustomSort dvs] = toJSON (dataValuesSpecs dvs)-sortPropertySpec sps = object (concatMap sortProperty sps)----- | Position channel properties used for creating a position channel encoding.--data PositionChannel-    = PName T.Text-      -- ^ Name of the field used for encoding with a position channel.-    | PHeight-      -- ^ Set the position to the height of the enclosing data space. Useful for placing-      --   a mark relative to the bottom edge of a view.-      ---      --   @since 0.4.0.0-    | PWidth-      -- ^ Set the position to the width of the enclosing data space. Useful for justifying-      --   a mark to the right hand edge of a view. e.g. to position a mark at the right of-      --   the data rectangle:-      ---      -- @-      -- enc =-      --   'encoding'-      --      . 'position' 'X' [ PWidth ]-      -- @-      ---      --   @since 0.4.0.0-    | PNumber Double-      -- ^ Set a position to an arbitrary value. Useful for placing items at the top of-      --   a plot area (@PNumber 0@) or a fixed number of pixels from the top.-      --   See also 'PHeight' and 'PWidth'.-      ---      --   @since 0.4.0.0-    | PRepeat Arrangement-      -- ^ Reference in a position channel to a field name generated by 'repeatFlow'-      --   or 'repeat'. The parameter identifies whether reference is being made to-      --   fields that are to be arranged in columns, in rows, or a with a flow layout.-      ---      --   For example:-      ---      -- @-      -- enc =-      --   'encoding'-      --      . 'position' 'X' [ PRepeat 'Flow', 'PmType' 'Quantitative' ]-      ---      -- spec =-      --    'asSpec' [ dataVals [], 'mark' 'Tick' [], enc [] ]-      ---      -- 'toVegaLite'-      --    [ 'repeatFlow' [ \"Horsepower\", \"Miles_per_Gallon\", \"Acceleration\"]-      --    , 'specification' spec-      --    ]-      -- @-    | PmType Measurement-      -- ^ Level of measurement when encoding with a position channel.-    | PBin [BinProperty]-      -- ^ Discretize numeric values into bins when encoding with a-      --   position channel.-      ---      --   For example, to encode a frequency histogram with bins every 5 units:-      ---      --   @-      --   enc = 'encoding'-      --           . 'position' 'X' [ 'PName' \"x\"-      --                        , 'PmType' 'Ordinal'-      --                        , 'PBin' ['Step' 5]-      --                        ]-      --           . 'position' 'Y' [ 'PmType' 'Quantitative'-      --                        , 'PAggregate' 'Count'-      --                        ]-      --   @-    | PBinned-      -- ^ Indicate that the data encoded with position is already binned.-      ---      --   @since 0.4.0.0-    | PTimeUnit TimeUnit-      -- ^ Form of time unit aggregation of field values when encoding with a position channel.-    | PTitle T.Text-      -- ^ Title of a field when encoding with a position channel.-      ---      --   @since 0.4.0.0-    | PNoTitle-      -- ^ Draw no title.-      ---      -- @since 0.4.0.0-    | PAggregate Operation-      -- ^ Compute some aggregate summary statistics for a field to be encoded-      --   with a position channel.-      ---      --   @-      --   enc = 'encoding'-      --           . 'position' 'X' [ 'PName' \"role\", 'PmType' 'Ordinal' ]-      --           . 'position' 'Y' [ 'PName' \"salary\"-      --                        , 'PmType' 'Quantitative'-      --                        , 'PAggregate' 'Mean'-      --                        ]-      --   @-    | PScale [ScaleProperty]-      -- ^ Scaling applied to a field when encoding with a position channel.-      --   The scale will transform a field's value into a position along-      --   one axis.-      ---      --   For example, the following will scale the bars positioned along-      --   a horizontal axis to have an inner spacing of 50% (0.5) of the-      --   total space allocated to each bar:-      ---      --   @-      --   enc = 'encoding'-      --           . 'position' 'X' [ 'PName' \"ageGroup\"-      --                        , 'PmType' 'Nominal'-      --                        , 'PScale' ['SPaddingInner' 0.5]-      --                        ]-      --   @-    | PAxis [AxisProperty]-      -- ^ Axis properties used when encoding with a position channel. For no axis,-      --   provide an empty list.-    | PSort [SortProperty]-      -- ^ Sort order for field when encoding with a position channel.-    | PStack StackOffset-      -- ^ Type of stacking offset for the field when encoding with a-      --   position channel.-      ---      --   For example, stacking areas away from a centreline can be used-      --   to create a-      --   [streamgraph](https://vega.github.io/vega-lite/examples/stacked_area_stream.html):-      ---      --   @-      --   enc = 'encoding'-      --           . 'position' 'X' ['PName' \"week\", 'PmType' 'Ordinal']-      --           . 'position' 'Y' [ 'PName' \"takings\"-      --                        , 'PmType' 'Quantitative'-      --                        , 'PStack' 'StCenter'-      --                        ]-      --           . 'color' ['MName' \"shop\", 'MmType' 'Nominal']-      --   @-      ---      --   Changed from @StackProperty@ in version @0.4.0.0@.-    | PImpute [ImputeProperty]-      -- ^ Set the imputation rules for a position channel. See the-      --   [Vega-Lite impute documentation](https://vega.github.io/vega-lite/docs/impute.html).-      ---      --   @since 0.4.0.0---positionChannelProperty :: PositionChannel -> LabelledSpec-positionChannelProperty (PName s) = field_ s-positionChannelProperty (PmType m) = mtype_ m-positionChannelProperty (PBin b) = bin b-positionChannelProperty PBinned = binned_-positionChannelProperty (PAggregate op) = aggregate_ op-positionChannelProperty (PTimeUnit tu) = timeUnit_ tu-positionChannelProperty (PTitle s) = "title" .= s-positionChannelProperty PNoTitle = "title" .= A.Null-positionChannelProperty (PSort ops) = sort_ ops-positionChannelProperty (PScale sps) = scaleProp_ sps-positionChannelProperty (PAxis aps) =-  let js = if null aps-           then A.Null-           else object (map axisProperty aps)-  in "axis" .= js-positionChannelProperty (PStack so) = stackOffset so-positionChannelProperty (PRepeat arr) = "field" .= object [repeat_ arr]-positionChannelProperty PHeight = value_ "height"-positionChannelProperty PWidth = value_ "width"-positionChannelProperty (PNumber x) = "value" .= x-positionChannelProperty (PImpute ips) = impute_ ips---measurementLabel :: Measurement -> T.Text-measurementLabel Nominal = "nominal"-measurementLabel Ordinal = "ordinal"-measurementLabel Quantitative = "quantitative"-measurementLabel Temporal = "temporal"-measurementLabel GeoFeature = "geojson"---positionLabel :: Position -> T.Text-positionLabel X = "x"-positionLabel Y = "y"-positionLabel X2 = "x2"-positionLabel Y2 = "y2"-positionLabel XError     = "xError"-positionLabel YError     = "yError"-positionLabel XError2    = "xError2"-positionLabel YError2    = "yError2"-positionLabel Longitude = "longitude"-positionLabel Latitude = "latitude"-positionLabel Longitude2 = "longitude2"-positionLabel Latitude2 = "latitude2"---{-|--Set the background color of the visualization. Should be specified with a CSS-string such as @\"#ffe\"@ or @\"rgb(200,20,150)\"@. If not specified the background will-be transparent.--@-'toVegaLite'-    [ 'background' "rgb(251,247,238)"-    , 'dataFromUrl' "data/population.json" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-background :: T.Text -> PropertySpec-background colour = (VLBackground, toJSON colour)---{-|--Provides an optional description to be associated with the visualization.--@-'toVegaLite'-    [ 'description' "Population change of key regions since 1900"-    , 'dataFromUrl' "data/population.json" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-description :: T.Text -> PropertySpec-description s = (VLDescription, toJSON s)----- | Optional metadata.------   @since 0.4.0.0--usermetadata ::-  A.Object-  -- ^ The metadata is passed around but ignored by VegaLite.-  -> PropertySpec-usermetadata o = (VLUserMetadata, A.Object o)---{-|--Provide an optional title to be displayed in the visualization.--@-'toVegaLite'-    [ 'title' "Population Growth" ['TColor' \"orange\"]-    , 'dataFromUrl' \"data/population.json\" []-    , 'mark' 'Bar' []-    , 'encoding' ...-    ]-@--Prior to @0.4.0.0@ there was no way to set the title options-(other than using 'configuration' with 'TitleStyle').---}-title ::-  T.Text-  -> [TitleConfig]-  -- ^ Configure the appearance of the title.-  ---  --   @since 0.4.0.0-  -> PropertySpec-title s [] = (VLTitle, toJSON s)-title s topts = (VLTitle,-                 object ("text" .= s : map titleConfigSpec topts))---{-|--Axis customisation properties. These are used for customising individual axes.-To configure all axes, use 'AxisConfig' with a 'configuration' instead. See the-<https://vega.github.io/vega-lite/docs/axis.html#axis-properties Vega-Lite documentation>-for more details.--The @AxTitleMaxLength@ constructor was removed in release @0.4.0.0@. The-'AxTitleLimit' constructor should be used instead.---}-{-# DEPRECATED AxDates "Please change AxDates to AxValues" #-}-data AxisProperty-    = AxBandPosition Double-      -- ^ An interpolation fraction indicating where, for @band@ scales, axis ticks should-      --   be position. A value of @0@ places ticks at the left-edge of the band, @0.5@ in-      --   the middle, and @1@ at the right edge.-      ---      --   @since 0.4.0.0-    | AxDomain Bool-      -- ^ Should the axis domain (the baseline) be displayed?-    | AxDomainColor Color-      -- ^ The axis domain color.-      ---      --   @since 0.4.0.0-    | AxDomainDash [Double]-      -- ^ The dash style of the domain (alternating stroke, space lengths-      --   in pixels).-      ---      --   @since 0.4.0.0-    | AxDomainDashOffset Double-      -- ^ The pixel offset at which to start drawing the domain dash array.-      ---      --   @since 0.4.0.0-    | AxDomainOpacity Opacity-      -- ^ The axis domain opacity.-      ---      --   @since 0.4.0.0-    | AxDomainWidth Double-      -- ^ The width of the axis domain.-      ---      --   @since 0.4.0.0-    | AxFormat T.Text-      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html) for-      --   axis values. To distinguish between formatting as numeric values-      --   and data/time values, additionally use 'AxFormatAsNum' or 'AxFormatAsTemporal'.-    | AxFormatAsNum-      -- ^ Facet headers should be formatted as numbers. Use a-      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)-      --   with 'AxFormat'.-      ---      -- @since 0.4.0.0-    | AxFormatAsTemporal-      -- ^ Facet headers should be formatted as dates or times. Use a-      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)-      --   with 'AxFormat'.-      ---      -- @since 0.4.0.0-    | AxGrid Bool-      -- ^ Should an axis grid be displayed?-    | AxGridColor Color-      -- ^ The color for the grid.-      ---      --   @since 0.4.0.0-    | AxGridDash [Double]-      -- ^ The dash style of the grid (alternating stroke, space lengths-      --   in pixels).-      ---      --   @since 0.4.0.0-    | AxGridDashOffset Double-      -- ^ The pixel offset at which to start drawing the grid dash array.-      ---      --   @since 0.4.0.0-    | AxGridOpacity Opacity-      -- ^ The opacity of the grid.-      ---      --   @since 0.4.0.0-    | AxGridWidth Double-      -- ^ The width of the grid lines.-      ---      --   @since 0.4.0.0-    | AxLabels Bool-      -- ^ Should labels be added to an axis?-    | AxLabelAlign HAlign-      -- ^ The horizontal alignment for labels.-      ---      --   @since 0.4.0.0-    | AxLabelAngle Angle-      -- ^ The angle at which to draw labels.-    | AxLabelBaseline VAlign-      -- ^ The vertical alignment for labels.-      ---      --   @since 0.4.0.0-    | AxLabelNoBound-      -- ^ No boundary overlap check is applied to labels. This is the-      --   default behavior.-      ---      --   See also 'AxLabelBound' and 'AxLabelBoundValue'.-      ---      --   @since 0.4.0.0-    | AxLabelBound-      -- ^ Labels are hidden if they exceed the axis range by more than 1-      --   pixel.-      ---      --   See also 'AxLabelNoBound' and 'AxLabelBoundValue'.-      ---      --   @since 0.4.0.0-    | AxLabelBoundValue Double-      -- ^ Labels are hidden if they exceed the axis range by more than-      --   the given number of pixels.-      ---      --   See also 'AxLabelNoBound' and 'AxLabelBound'.-      ---      --   @since 0.4.0.0-    | AxLabelColor Color-      -- ^ The label color.-      ---      --   @since 0.4.0.0-    | AxLabelNoFlush-      -- ^ The labels are not aligned flush to the scale. This is the-      --   default for non-continuous X scales.-      ---      --   See also 'AxLabelFlush' and 'AxLabelFlushValue'.-      ---      --   @since 0.4.0.0-    | AxLabelFlush-      -- ^ The first and last axis labels are aligned flush to the scale-      --   range.-      ---      --   See also 'AxLabelNoFlush' and 'AxLabelFlushValue'.-      ---      --   @since 0.4.0.0-    | AxLabelFlushValue Double-      -- ^ The labels are aligned flush, and the parameter determines-      --   the extra offset, in pixels, to apply to the first and last-      --   labels. This can help the labels better group (visually) with-      --   the corresponding axis ticks.-      ---      --   See also 'AxLabelNoFlush' and 'AxLabelFlush'.-      ---      --   @since 0.4.0.0-    | AxLabelFlushOffset Double-      -- ^ The number of pixels to offset flush-adjusted labels.-      ---      --   @since 0.4.0.0-    | AxLabelFont T.Text-      -- ^ The font for the label.-      ---      --   @since 0.4.0.0-    | AxLabelFontSize Double-      -- ^ The font size of the label.-      ---      --   @since 0.4.0.0-    | AxLabelFontStyle T.Text-      -- ^ The font style of the label.-      ---      --   @since 0.4.0.0-    | AxLabelFontWeight FontWeight-      -- ^ The font weight of the label.-      ---      --   @since 0.4.0.0-    | AxLabelLimit Double-      -- ^ The maximum width of a label, in pixels.-      ---      --   @since 0.4.0.0-    | AxLabelOpacity Opacity-      -- ^ The opacity of the label.-      ---      --   @since 0.4.0.0-    | AxLabelOverlap OverlapStrategy-      -- ^ How should overlapping labels be displayed?-    | AxLabelPadding Double-      -- ^ The padding, in pixels, between the label and the axis.-    | AxLabelSeparation Double-      -- ^ The minimum separation, in pixels, between label bounding boxes-      --   for them to be considered non-overlapping. This is ignored if-      --   the 'AxLabelOverlap' strategy is 'ONone'.-      ---      --   @since 0.4.0.0-    | AxMaxExtent Double-      -- ^ The maximum extent, in pixels, that axis ticks and labels should use.-      --   This determines a maxmium offset value for axis titles.-    | AxMinExtent Double-      -- ^ The minimum extent, in pixels, that axis ticks and labels should use.-      --   This determines a minmium offset value for axis titles.-    | AxOffset Double-      -- ^ The offset, in pixels, between the axis and the edge of the-      --   enclosing group or data rectangle.-    | AxOrient Side-      -- ^ The orientation of the axis.-    | AxPosition Double-      -- ^ The anchor position of the axis in pixels.-    | AxTicks Bool-      -- ^ Should tick marks be drawn on an axis?-    | AxTickColor Color-      -- ^ The color of the ticks.-      ---      --   @since 0.4.0.0-    | AxTickCount Int-      -- ^ The desired number of ticks for axes visualizing quantitative scales.-      --   This is a hint to the system, and the actual number used will be-      --   adjusted to be \"nice\" (multiples of 2, 5, or 10) and lie within the-      --   underlying scale's range.-    | AxTickDash [Double]-      -- ^ The dash style of the ticks (alternating stroke, space lengths-      --   in pixels).-      ---      --   @since 0.4.0.0-    | AxTickDashOffset Double-      -- ^ The pixel offset at which to start drawing the tick dash array.-      ---      --   @since 0.4.0.0-    | AxTickExtra Bool-      -- ^ Should an extra axis tick mark be added for the initial position of-      --   the axis?-      ---      --   @since 0.4.0.0-    | AxTickMinStep Double-      -- ^ The minimum desired step between axis ticks, in terms of the scale-      --   domain values.-      ---      --   @since 0.4.0.0-    | AxTickOffset Double-      -- ^ The position offset, in pixels, to apply to ticks, labels, and grid lines.-      ---      --   @since 0.4.0.0-    | AxTickOpacity Opacity-      -- ^ The opacity of the ticks.-      ---      --   @since 0.4.0.0-    | AxTickRound Bool-      -- ^ Should pixel position values be rounded to the nearest integer?-      ---      --   @since 0.4.0.0-    | AxTickSize Double-      -- ^ The size of the tick marks in pixels.-    | AxTickWidth Double-      -- ^ The width of the tick marks in pixels.-      ---      --   @since 0.4.0.0-    | AxTitle T.Text-      -- ^ The axis title.-    | AxNoTitle-      -- ^ Draw no title for the axis.-      ---      --   @since 0.4.0.0-    | AxTitleAlign HAlign-      -- ^ The horizontal alignment of the axis title.-    | AxTitleAnchor APosition-      -- ^ The text anchor position for placing axis titles.-      ---      --   @since 0.4.0.0-    | AxTitleAngle Angle-      -- ^ The angle of the axis title.-    | AxTitleBaseline VAlign-      -- ^ The vertical alignment of the axis title.-      ---      --   @since 0.4.0.0-    | AxTitleColor Color-      -- ^ The color of the axis title.-      ---      --   @since 0.4.0.0-    | AxTitleFont T.Text-      -- ^ The font for the axis title.-      ---      --   @since 0.4.0.0-    | AxTitleFontSize Double-      -- ^ The font size of the axis title.-      ---      --   @since 0.4.0.0-    | AxTitleFontStyle T.Text-      -- ^ The font style of the axis title.-      ---      --   @since 0.4.0.0-    | AxTitleFontWeight FontWeight-      -- ^ The font weight of the axis title.-      ---      --   @since 0.4.0.0-    | AxTitleLimit Double-      -- ^ The maximum allowed width of the axis title, in pixels.-      ---      --   @since 0.4.0.0-    | AxTitleOpacity Opacity-      -- ^ The opacity of the axis title.-      ---      --   @since 0.4.0.0-    | AxTitlePadding Double-      -- ^ The padding, in pixels, between title and axis.-    | AxTitleX Double-      -- ^ The X coordinate of the axis title, relative to the axis group.-      ---      --   @since 0.4.0.0-    | AxTitleY Double-      -- ^ The Y coordinate of the axis title, relative to the axis group.-      ---      --   @since 0.4.0.0-    | AxValues DataValues-      -- ^ Set the explicit tick, grid, and label values along an axis.-      ---      --   The following three examples are for an axis displaying a-      --   quantitative, categorical, and temporal field respectively.-      ---      --   @-      --   'PAxis' ['AxValues' ('Numbers' [2, 3, 5, 7, 11, 13, 17])]-      --   'PAxis' ['AxValues' ('Strings' ["cats", "dogs", "elephants"])]-      --   'PAxis' ['AxValues' ('DateTimes' [ ['DTYear' 2019, 'DTMonth' 'Mar', 'DTDate' 31]-      --                              , ['DTYear' 2019, 'DTMonth' 'Jun', 'DTDate' 30]-      --                              , ['DTYear' 2019, 'DTMonth' 'Sep', 'DTDate' 30]-      --                              ])]-      --   @-      ---      --   Changed in @0.4.0.0@ to take 'DataValues' rather than @[Double]@.-    | AxDates [[DateTime]]-      -- ^ The dates or times to appear along the axis.-      ---      --   As of version @0.4.0.0@, this is deprecated. The 'AxValues'-      --   constructor should be used instead.-    | AxZIndex ZIndex-      -- ^ The z-index of the axis, relative to the chart marks.---axisProperty :: AxisProperty -> LabelledSpec-axisProperty (AxBandPosition x) = "bandPosition" .= x-axisProperty (AxDomain b) = "domain" .= b-axisProperty (AxDomainColor s) = "domainColor" .= s-axisProperty (AxDomainDash ds) = "domainDash" .= ds-axisProperty (AxDomainDashOffset x) = "domainDashOffset" .= x-axisProperty (AxDomainOpacity x) = "domainOpacity" .= x-axisProperty (AxDomainWidth x) = "domainWidth" .= x-axisProperty (AxFormat fmt) = "format" .= fmt-axisProperty AxFormatAsNum = "formatType" .= fromT "number"-axisProperty AxFormatAsTemporal = "formatType" .= fromT "time"-axisProperty (AxGrid b) = "grid" .= b-axisProperty (AxGridColor s) = "gridColor" .= s-axisProperty (AxGridDash ds) = "gridDash" .= ds-axisProperty (AxGridDashOffset x) = "gridDashOffset" .= x-axisProperty (AxGridOpacity x) = "gridOpacity" .= x-axisProperty (AxGridWidth x) = "gridWidth" .= x-axisProperty (AxLabels b) = "labels" .= b-axisProperty (AxLabelAlign ha) = "labelAlign" .= hAlignLabel ha-axisProperty (AxLabelAngle a) = "labelAngle" .= a-axisProperty (AxLabelBaseline va) = "labelBaseline" .= vAlignLabel va-axisProperty AxLabelNoBound = "labelBound" .= False-axisProperty AxLabelBound = "labelBound" .= True-axisProperty (AxLabelBoundValue x) = "labelBound" .= x-axisProperty (AxLabelColor s) = "labelColor" .= s-axisProperty AxLabelNoFlush = "labelFlush" .= False-axisProperty AxLabelFlush = "labelFlush" .= True-axisProperty (AxLabelFlushValue x) = "labelFlush" .= x-axisProperty (AxLabelFlushOffset x) = "labelFlushOffset" .= x-axisProperty (AxLabelFont s) = "labelFont" .= s-axisProperty (AxLabelFontSize x) = "labelFontSize" .= x-axisProperty (AxLabelFontStyle s) = "labelFontStyle" .= s-axisProperty (AxLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw-axisProperty (AxLabelLimit x) = "labelLimit" .= x-axisProperty (AxLabelOpacity x) = "labelOpacity" .= x-axisProperty (AxLabelOverlap s) = "labelOverlap" .= overlapStrategyLabel s-axisProperty (AxLabelPadding x) = "labelPadding" .= x-axisProperty (AxLabelSeparation x) = "labelSeparation" .= x-axisProperty (AxMaxExtent n) = "maxExtent" .= n-axisProperty (AxMinExtent n) = "minExtent" .= n-axisProperty (AxOffset n) = "offset" .= n-axisProperty (AxOrient side) = "orient" .= sideLabel side-axisProperty (AxPosition n) = "position" .= n-axisProperty (AxTicks b) = "ticks" .= b-axisProperty (AxTickColor s) = "tickColor" .= s-axisProperty (AxTickCount n) = "tickCount" .= n-axisProperty (AxTickDash ds) = "tickDash" .= ds-axisProperty (AxTickDashOffset x) = "tickDashOffset" .= x-axisProperty (AxTickExtra b) = "tickExtra" .= b-axisProperty (AxTickMinStep x) = "tickMinStep" .= x-axisProperty (AxTickOffset x) = "tickOffset" .= x-axisProperty (AxTickOpacity x) = "tickOpacity" .= x-axisProperty (AxTickRound b) = "tickRound" .= b-axisProperty (AxTickSize x) = "tickSize" .= x-axisProperty (AxTickWidth x) = "tickWidth" .= x-axisProperty (AxTitle ttl) = "title" .= ttl-axisProperty AxNoTitle = "title" .= A.Null-axisProperty (AxTitleAlign ha) = "titleAlign" .= hAlignLabel ha-axisProperty (AxTitleAnchor a) = "titleAnchor" .= anchorLabel a-axisProperty (AxTitleAngle x) = "titleAngle" .= x-axisProperty (AxTitleBaseline va) = "titleBaseline" .= vAlignLabel va-axisProperty (AxTitleColor s) = "titleColor" .= s-axisProperty (AxTitleFont s) = "titleFont" .= s-axisProperty (AxTitleFontSize x) = "titleFontSize" .= x-axisProperty (AxTitleFontStyle s) = "titleFontStyle" .= s-axisProperty (AxTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw-axisProperty (AxTitleLimit x) = "titleLimit" .= x-axisProperty (AxTitleOpacity x) = "titleOpacity" .= x-axisProperty (AxTitlePadding pad) = "titlePadding" .= pad-axisProperty (AxTitleX x) = "titleX" .= x-axisProperty (AxTitleY x) = "titleY" .= x-axisProperty (AxValues vals) = "values" .= dataValuesSpecs vals-axisProperty (AxDates dtss) = "values" .= map (object . map dateTimeProperty) dtss-axisProperty (AxZIndex z) = "zindex" .= z----- | Indicates the horizontal alignment of text such as on an axis or legend.--data HAlign-    = AlignCenter-    | AlignLeft-    | AlignRight----- | Indicates the vertical alignment of text that may be attached to a mark.--data VAlign-    = AlignTop-    | AlignMiddle-    | AlignBottom---hAlignLabel :: HAlign -> T.Text-hAlignLabel AlignLeft = "left"-hAlignLabel AlignCenter = "center"-hAlignLabel AlignRight = "right"---vAlignLabel :: VAlign -> T.Text-vAlignLabel AlignTop = "top"-vAlignLabel AlignMiddle = "middle"-vAlignLabel AlignBottom = "bottom"----- | Represents one side of a rectangular space.--data Side-    = STop-    | SBottom-    | SLeft-    | SRight---sideLabel :: Side -> T.Text-sideLabel STop = "top"-sideLabel SBottom = "bottom"-sideLabel SLeft = "left"-sideLabel SRight = "right"---{-|--Type of overlap strategy to be applied when there is not space to show all items-on an axis. See the-<https://vega.github.io/vega-lite/docs/axis.html#labels Vega-Lite documentation>-for more details.--}--data OverlapStrategy-    = ONone-      -- ^ No overlap strategy to be applied when there is not space to show all items-      --   on an axis.-    | OParity-      -- ^ Give all items equal weight in overlap strategy to be applied when there is-      --   not space to show them all on an axis.-    | OGreedy-      -- ^ Greedy overlap strategy to be applied when there is not space to show all-      --   items on an axis.--overlapStrategyLabel :: OverlapStrategy -> T.Text-overlapStrategyLabel ONone = "false"-overlapStrategyLabel OParity = "parity"-overlapStrategyLabel OGreedy = "greedy"---{-|--Allows a date or time to be represented. This is typically part of a list of-@DateTime@ items to provide a specific point in time. For details see the-<https://vega.github.io/vega-lite/docs/types.html#datetime Vega-Lite documentation>.--}--data DateTime-    = DTYear Int-    | DTQuarter Int-    | DTMonth MonthName-    | DTDate Int-    | DTDay DayName-    | DTHours Int-    | DTMinutes Int-    | DTSeconds Int-    | DTMilliseconds Int----- | Identifies the day of the week.--data DayName-    = Mon-    | Tue-    | Wed-    | Thu-    | Fri-    | Sat-    | Sun----- | Identifies a month of the year.--data MonthName-    = Jan-    | Feb-    | Mar-    | Apr-    | May-    | Jun-    | Jul-    | Aug-    | Sep-    | Oct-    | Nov-    | Dec---{-|--Describes a unit of time. Useful for encoding and transformations. See the-<https://vega.github.io/vega-lite/docs/timeunit.html Vega-Lite documentation>-for further details.--@-'encoding'-    . 'position' 'X' [ 'PName' "date", 'PmType' 'Temporal', 'PTimeUnit' ('Utc' 'YearMonthDateHours') ]-@--}--data TimeUnit-    = Year-    | YearQuarter-    | YearQuarterMonth-    | YearMonth-    | YearMonthDate-    | YearMonthDateHours-    | YearMonthDateHoursMinutes-    | YearMonthDateHoursMinutesSeconds-    | Quarter-    | QuarterMonth-    | Month-    | MonthDate-    | Date-    | Day-    | Hours-    | HoursMinutes-    | HoursMinutesSeconds-    | Minutes-    | MinutesSeconds-    | Seconds-    | SecondsMilliseconds-    | Milliseconds-    | Utc TimeUnit-      -- ^ Encode a time as UTC (coordinated universal time, independent of local time-      --   zones or daylight saving).---dateTimeProperty :: DateTime -> LabelledSpec-dateTimeProperty (DTYear y) = "year" .= y-dateTimeProperty (DTQuarter q) = "quarter" .= q-dateTimeProperty (DTMonth mon) = "month" .= monthNameLabel mon-dateTimeProperty (DTDate dt) = "date" .= dt-dateTimeProperty (DTDay day) = "day" .= dayLabel day-dateTimeProperty (DTHours h) = "hours" .= h-dateTimeProperty (DTMinutes m) = "minutes" .= m-dateTimeProperty (DTSeconds s) = "seconds" .= s-dateTimeProperty (DTMilliseconds ms) = "milliseconds" .= ms---dayLabel :: DayName -> T.Text-dayLabel Mon = "Mon"-dayLabel Tue = "Tue"-dayLabel Wed = "Wed"-dayLabel Thu = "Thu"-dayLabel Fri = "Fri"-dayLabel Sat = "Sat"-dayLabel Sun = "Sun"---monthNameLabel :: MonthName -> T.Text-monthNameLabel Jan = "Jan"-monthNameLabel Feb = "Feb"-monthNameLabel Mar = "Mar"-monthNameLabel Apr = "Apr"-monthNameLabel May = "May"-monthNameLabel Jun = "Jun"-monthNameLabel Jul = "Jul"-monthNameLabel Aug = "Aug"-monthNameLabel Sep = "Sep"-monthNameLabel Oct = "Oct"-monthNameLabel Nov = "Nov"-monthNameLabel Dec = "Dec"---timeUnitLabel :: TimeUnit -> T.Text-timeUnitLabel Year = "year"-timeUnitLabel YearQuarter = "yearquarter"-timeUnitLabel YearQuarterMonth = "yearquartermonth"-timeUnitLabel YearMonth = "yearmonth"-timeUnitLabel YearMonthDate = "yearmonthdate"-timeUnitLabel YearMonthDateHours = "yearmonthdatehours"-timeUnitLabel YearMonthDateHoursMinutes = "yearmonthdatehoursminutes"-timeUnitLabel YearMonthDateHoursMinutesSeconds = "yearmonthdatehoursminutesseconds"-timeUnitLabel Quarter = "quarter"-timeUnitLabel QuarterMonth = "quartermonth"-timeUnitLabel Month = "month"-timeUnitLabel MonthDate = "monthdate"-timeUnitLabel Date = "date"-timeUnitLabel Day = "day"-timeUnitLabel Hours = "hours"-timeUnitLabel HoursMinutes = "hoursminutes"-timeUnitLabel HoursMinutesSeconds = "hoursminutesseconds"-timeUnitLabel Minutes = "minutes"-timeUnitLabel MinutesSeconds = "minutesseconds"-timeUnitLabel Seconds = "seconds"-timeUnitLabel SecondsMilliseconds = "secondsmilliseconds"-timeUnitLabel Milliseconds = "milliseconds"-timeUnitLabel (Utc tu) = "utc" <> timeUnitLabel tu---{-|--Represents the type of cursor to display. For an explanation of each type,-see the-<https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#Keyword%20values CSS documentation>.---}-data Cursor-    = CAuto-    | CDefault-    | CNone-    | CContextMenu-    | CHelp-    | CPointer-    | CProgress-    | CWait-    | CCell-    | CCrosshair-    | CText-    | CVerticalText-    | CAlias-    | CCopy-    | CMove-    | CNoDrop-    | CNotAllowed-    | CAllScroll-    | CColResize-    | CRowResize-    | CNResize-    | CEResize-    | CSResize-    | CWResize-    | CNEResize-    | CNWResize-    | CSEResize-    | CSWResize-    | CEWResize-    | CNSResize-    | CNESWResize-    | CNWSEResize-    | CZoomIn-    | CZoomOut-    | CGrab-    | CGrabbing---cursorLabel :: Cursor -> T.Text-cursorLabel CAuto = "auto"-cursorLabel CDefault = "default"-cursorLabel CNone = "none"-cursorLabel CContextMenu = "context-menu"-cursorLabel CHelp = "help"-cursorLabel CPointer = "pointer"-cursorLabel CProgress = "progress"-cursorLabel CWait = "wait"-cursorLabel CCell = "cell"-cursorLabel CCrosshair = "crosshair"-cursorLabel CText = "text"-cursorLabel CVerticalText = "vertical-text"-cursorLabel CAlias = "alias"-cursorLabel CCopy = "copy"-cursorLabel CMove = "move"-cursorLabel CNoDrop = "no-drop"-cursorLabel CNotAllowed = "not-allowed"-cursorLabel CAllScroll = "all-scroll"-cursorLabel CColResize = "col-resize"-cursorLabel CRowResize = "row-resize"-cursorLabel CNResize = "n-resize"-cursorLabel CEResize = "e-resize"-cursorLabel CSResize = "s-resize"-cursorLabel CWResize = "w-resize"-cursorLabel CNEResize = "ne-resize"-cursorLabel CNWResize = "nw-resize"-cursorLabel CSEResize = "se-resize"-cursorLabel CSWResize = "sw-resize"-cursorLabel CEWResize = "ew-resize"-cursorLabel CNSResize = "ns-resize"-cursorLabel CNESWResize = "nesw-resize"-cursorLabel CNWSEResize = "nwse-resize"-cursorLabel CZoomIn = "zoom-in"-cursorLabel CZoomOut = "zoom-out"-cursorLabel CGrab = "grab"-cursorLabel CGrabbing = "grabbing"----- | Indicates the weight options for a font.--data FontWeight-    = Bold-    | Bolder-    | Lighter-    | Normal-    | W100-    | W200-    | W300-    | W400-    | W500-    | W600-    | W700-    | W800-    | W900---fontWeightSpec :: FontWeight -> VLSpec-fontWeightSpec Bold = fromT "bold"-fontWeightSpec Bolder = fromT "bolder"-fontWeightSpec Lighter = fromT "lighter"-fontWeightSpec Normal = fromT "normal"-fontWeightSpec W100 = fromF 100-fontWeightSpec W200 = fromF 200-fontWeightSpec W300 = fromF 300-fontWeightSpec W400 = fromF 400-fontWeightSpec W500 = fromF 500-fontWeightSpec W600 = fromF 600-fontWeightSpec W700 = fromF 700-fontWeightSpec W800 = fromF 800-fontWeightSpec W900 = fromF 900---{-|--Indicates mark interpolation style. See the-<https://vega.github.io/vega-lite/docs/mark.html#mark-def Vega-Lite documentation>-for details.--}-data MarkInterpolation-    = Basis-    | BasisClosed-    | BasisOpen-    | Bundle-    | Cardinal-    | CardinalClosed-    | CardinalOpen-    | Linear-    | LinearClosed-    | Monotone-    | StepAfter-    | StepBefore-    | Stepwise---markInterpolationLabel :: MarkInterpolation -> T.Text-markInterpolationLabel Linear = "linear"-markInterpolationLabel LinearClosed = "linear-closed"-markInterpolationLabel Stepwise = "step"-markInterpolationLabel StepBefore = "step-before"-markInterpolationLabel StepAfter = "step-after"-markInterpolationLabel Basis = "basis"-markInterpolationLabel BasisOpen = "basis-open"-markInterpolationLabel BasisClosed = "basis-closed"-markInterpolationLabel Cardinal = "cardinal"-markInterpolationLabel CardinalOpen = "cardinal-open"-markInterpolationLabel CardinalClosed = "cardinal-closed"-markInterpolationLabel Bundle = "bundle"-markInterpolationLabel Monotone = "monotone"---{-|--The orientation of an item. This is used with:-'BLeLDirection', 'LDirection',-'LeGradientDirection', 'LeLDirection', 'LeSymbolDirection',-and 'MOrient'.--In @0.4.0.0@ this was renamed from @MarkOrientation@ to 'Orientation'.---}---- based on schema 3.3.0 #/definitions/Orientation--data Orientation-    = Horizontal-      -- ^ Display horizontally.-    | Vertical-      -- ^ Display vertically.---orientationSpec :: Orientation -> VLSpec-orientationSpec Horizontal = "horizontal"-orientationSpec Vertical = "vertical"---{-|--Indicates the extent of the rule used for the error bar.  See-<https://vega.github.io/vega-lite/docs/errorbar.html#properties Vega-Lite documentation>-for details.--Note that not all options are valid for all mark types.--This is called @SummaryExtent@ in Elm and the constructors also have-different names.--@since 0.4.0.0--}---- based on schema 3.3.0 #/definitions/ErrorBarExtent---          (ConfidenceInterval to Iqr)--- and combined with the box/band "min-max" and IQR scaling values-----data MarkErrorExtent-  = ConfidenceInterval-    -- ^ Band extent between the 95% confidence intervals of a distribution.-  | StdErr-    -- ^ Band extent as the standard error about the mean of a distribution.-  | StdDev-    -- ^ Band extent as the standard deviation of a distribution.-  | Iqr-    -- ^ Band extent between the lower and upper quartiles of a distribution-    --   (the inter-quartile range, q1 to q3).-  | ExRange-    -- ^ Band extent between the minimum and maximum values in a distribution.-  | IqrScale Double-    -- ^ A scaling of the interquartile range to be used as whiskers in a-    --   'Boxplot'. For example @IqrScale 1.5@  would extend whiskers to-    --   ±1.5x the IQR from the mean.---- This is a little different from the other calls since I wanted to--- make sure the scale factor was encoded as a number not a string.----extent_ :: T.Text -> LabelledSpec-extent_ v = "extent" .= v--markErrorExtentLSpec :: MarkErrorExtent -> LabelledSpec-markErrorExtentLSpec ConfidenceInterval = extent_ "ci"-markErrorExtentLSpec StdErr             = extent_ "stderr"-markErrorExtentLSpec StdDev             = extent_ "stdev"-markErrorExtentLSpec Iqr                = extent_ "iqr"-markErrorExtentLSpec ExRange            = extent_ "min-max"-markErrorExtentLSpec (IqrScale sc)      = "extent" .= sc----- | Identifies the type of symbol used with the 'Point' mark type.---   It is used with 'MShape', 'LeSymbolType', and 'LSymbolType'.------   In version @0.4.0.0@ all constructors were changed to start---   with @Sym@.----data Symbol-    = SymCircle-      -- ^ Specify a circular symbol for a shape mark.-    | SymSquare-      -- ^ Specify a square symbol for a shape mark.-    | SymCross-      -- ^ Specify a cross symbol for a shape mark.-    | SymDiamond-      -- ^ Specify a diamond symbol for a shape mark.-    | SymTriangleUp-      -- ^ Specify an upward-triangular symbol for a shape mark.-    | SymTriangleDown-      -- ^ Specify a downward-triangular symbol for a shape mark.-    | SymTriangleRight-      -- ^ Specify an right-facing triangular symbol for a shape mark.-      ---      --   @since 0.4.0.0-    | SymTriangleLeft-      -- ^ Specify an left-facing triangular symbol for a shape mark.-      ---      --   @since 0.4.0.0-    | SymStroke-      -- ^ The line symbol.-      ---      --  @since 0.4.0.0-    | SymArrow-      -- ^ Centered directional shape.-      ---      --  @since 0.4.0.0-    | SymTriangle-      -- ^ Centered directional shape. It is not clear what difference-      --   this is to 'SymTriangleUp'.-      ---      --  @since 0.4.0.0-    | SymWedge-      -- ^ Centered directional shape.-      ---      --  @since 0.4.0.0-    | SymPath T.Text-      -- ^ A custom symbol shape as an-      --   [SVG path description](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).-      ---      --   For correct sizing, the path should be defined within a square-      --   bounding box, defined on an axis of -1 to 1 for both dimensions.---symbolLabel :: Symbol -> T.Text-symbolLabel SymCircle = "circle"-symbolLabel SymSquare = "square"-symbolLabel SymCross = "cross"-symbolLabel SymDiamond = "diamond"-symbolLabel SymTriangleUp = "triangle-up"-symbolLabel SymTriangleDown = "triangle-down"-symbolLabel SymTriangleRight = "triangle-right"-symbolLabel SymTriangleLeft = "triangle-left"-symbolLabel SymStroke = "stroke"-symbolLabel SymArrow = "arrow"-symbolLabel SymTriangle = "triangle"-symbolLabel SymWedge = "wedge"-symbolLabel (SymPath svgPath) = svgPath---{-|--Indicates the auto-sizing characteristics of the visualization such as amount-of padding, whether it should fill the parent container etc. For more details see the-<https://vega.github.io/vega-lite/docs/size.html#autosize Vega-Lite documentation>.---}--data Autosize-    = AContent-      -- ^ Interpret visualization dimensions to be for the data rectangle (external-      --   padding added to this size).-    | AFit-      -- ^ Interpret visualization dimensions to be for the entire visualization (data-      --   rectangle is shrunk to accommodate external decorations padding).-    | ANone-      -- ^ No autosizing is applied.-    | APad-      -- ^ Automatically expand size of visualization from the given dimensions in order-      --   to fit in all supplementary decorations (legends etc.).-    | APadding-      -- ^ Interpret visualization width to be for the entire visualization (data-      -- rectangle is shrunk to accommodate external padding).-    | AResize-      -- ^ Recalculate autosizing on every view update.---autosizeProperty :: Autosize -> LabelledSpec-autosizeProperty APad = ("type", fromT "pad")-autosizeProperty AFit = ("type", fromT "fit")-autosizeProperty ANone = ("type", fromT "none")-autosizeProperty AResize = "resize" .= True-autosizeProperty AContent = ("contains", fromT "content")-autosizeProperty APadding = ("contains", fromT "padding")---{-|--Declare the way the view is sized. See the-<https://vega.github.io/vega-lite/docs/size.html#autosize Vega-Lite documentation>-for details.--@-'toVegaLite'-    [ 'width' 250-    , 'height' 300-    , 'autosize' [ 'AFit', 'APadding', 'AResize' ]-    , 'dataFromUrl' "data/population.json" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-autosize :: [Autosize] -> PropertySpec-autosize aus = (VLAutosize, object (map autosizeProperty aus))----- | Indicates the style in which field names are displayed.--data FieldTitleProperty-    = Verbal-      -- ^ Creates \"Sum of field\", \"Year of date\", \"field (binned)\", etc.-    | Function-      -- ^ Creates \"SUM(field)\", \"YEAR(date)\", \"BIN(field)\", etc.-    | Plain-      -- ^ Just use the field name without any extra text.---fieldTitleLabel :: FieldTitleProperty -> T.Text-fieldTitleLabel Verbal = "verbal"-fieldTitleLabel Function = "functional"-fieldTitleLabel Plain = "plain"----- | Indicates the type of legend to create. It is used with 'LType'.------   Prior to version @0.4.0.0.0@ this was called @Legend@ and the---   constructors did not end in @Legend@.----data LegendType-    = GradientLegend-      -- ^ Typically used for continuous quantitative data.-    | SymbolLegend-      -- ^ Typically used for categorical data.---legendLabel :: LegendType -> T.Text-legendLabel GradientLegend = "gradient"-legendLabel SymbolLegend = "symbol"---{-|--Legend configuration options. For more detail see the-<https://vega.github.io/vega-lite/docs/legend.html#config Vega-Lite documentation>.--This data type has seen significant changes in the @0.4.0.0@ release:--- the @EntryPadding@, @GradientHeight@, @GradientLabelBaseline@, @GradientWidth@-  and @SymbolColor@ constructors were removed;--- the constructors were removed;--- the remaining constructors that did not begin with @Le@ were renamed (for-  example @Orient@ was changed to 'LeOrient');--- and new constructors were added.---}---- based on schema 3.3.0 #/definitions/LegendConfig--data LegendConfig-    = LeClipHeight Double-      -- ^ The height in pixels at which to clip symbol legend entries.-      ---      --   @since 0.4.0.0-    | LeColumnPadding Double-      -- ^ The horizontal padding, in pixels, between symbol legend entries.-      ---      --   @since 0.4.0.0-    | LeColumns Int-      -- ^ The number of columns in which to arrange symbol legend entries. A value-      --   of @0@ or lower indicates a single row with one column per entry.-      ---      --   @since 0.4.0.0-    | LeCornerRadius Double-      -- ^ The corner radius for the full legend.-    | LeFillColor Color-      -- ^ The background fill color for the full legend.-    | LeGradientDirection Orientation-      -- ^ The default direction for gradient legends.-      ---      --   @since 0.4.0.0-    | LeGradientHorizontalMaxLength Double-      -- ^ The maximum legend length for a horizontal gradient.-      ---      --   @since 0.4.0.0-    | LeGradientHorizontalMinLength Double-      -- ^ The minimum legend length for a horizontal gradient.-      ---      --   @since 0.4.0.0-    | LeGradientLabelLimit Double-      -- ^ The maximum allowed length, in pixels, of color-ramp gradient labels.-    | LeGradientLabelOffset Double-      -- ^ The vertical offset in pixels for color-ramp gradient labels.-    | LeGradientLength Double-      -- ^ The length in pixels of the primary axis of a color gradient.-      --   See also 'LeGradientThickness'.-      ---      --   @since 0.4.0.0-    | LeGradientOpacity Opacity-      -- ^ The opacity of the color gradient.-      ---      --   @since 0.4.0.0-    | LeGradientStrokeColor Color-      -- ^ The color of the gradient stroke.-    | LeGradientStrokeWidth Double-      -- ^ The width of the gradient stroke, in pixels.-    | LeGradientThickness Double-      -- ^ The thickness in pixels of the color gradient. See also 'LeGradientLength'.-      ---      --   @since 0.4.0.0-    | LeGradientVerticalMaxLength Double-      -- ^ The maximum legend length for a vertical gradient.-      ---      --   @since 0.4.0.0-    | LeGradientVerticalMinLength Double-      -- ^ The minimum legend length for a vertical gradient.-      ---      --   @since 0.4.0.0-    | LeGridAlign CompositionAlignment-      -- ^ The alignment to apply to symbol legends rows and columns.-      ---      --    @since 0.4.0.0-    | LeLabelAlign HAlign-      -- ^ The alignment of the legend label.-    | LeLabelBaseline VAlign-      -- ^ The position of the baseline of the legend label.-    | LeLabelColor Color-      -- ^ The color of the legend label.-    | LeLabelFont T.Text-      -- ^ The font of the legend label.-    | LeLabelFontSize Double-      -- ^ The font of the legend label.-    | LeLabelFontStyle T.Text-      -- ^ The font style of the legend label.-      ---      --   @since 0.4.0.0-    | LeLabelFontWeight FontWeight-      -- ^ The font weight of the legend label.-      ---      --   @since 0.4.0.0-    | LeLabelLimit Double-      -- ^ The maxumum allowed pixel width of the legend label.-    | LeLabelOffset Double-      -- ^ The offset of the legend label.-    | LeLabelOpacity Opacity-      -- ^ The opacity of the legend label.-      ---      --   @since 0.4.0.0-    | LeLabelOverlap OverlapStrategy-      -- ^ How to resolve overlap of labels in gradient legends.-      ---      --   @since 0.4.0.0-    | LeLabelPadding Double-      -- ^ The passing in pixels between the legend and legend labels.-      ---      --   @since 0.4.0.0-    | LeLabelSeparation Double-      -- ^ The minimum separation between label bounding boxes for them-      --   to be considered non-overlapping (ignored if 'ONone' is the-      --   chosen overlap strategy).-      ---      --   @since 0.4.0.0-    | LeLayout [LegendLayout]-      -- ^ Layout parameters for the legend orient group.-      ---      --   @since 0.4.0.0-     | LeLeX Double-      -- ^ Custom x position for a legend with orientation 'LONone'.-      ---      --   @since 0.4.0.0-     | LeLeY Double-      -- ^ Custom y position for a legend with orientation 'LONone'.-      ---      --   @since 0.4.0.0-    | LeOffset Double-      -- ^ The offset in pixels between the legend and the data rectangle-      --   and axes.-    | LeOrient LegendOrientation-      -- ^ The orientation of the legend.-    | LePadding Double-      -- ^ The padding between the border and content of the legend group.-    | LeRowPadding Double-      -- ^ The vertical padding in pixels between symbol legend entries.-      ---      --   @since 0.4.0.0-    | LeShortTimeLabels Bool-      -- ^ Should month and weekday names be abbreviated?-    | LeStrokeColor Color-      -- ^ The border stoke color for the full legend.-    | LeStrokeDash [Double]-      -- ^ The border stroke dash pattern for the full legend (alternating-      --   stroke, space lengths in pixels).-    | LeStrokeWidth Double-      -- ^ The border stroke width for the full legend.-    | LeSymbolBaseFillColor Color-      -- ^ The fill color for legend symbols. This is only applied if-      --   there is no \"fill\" scale color encoding for the legend.-      ---      --   @since 0.4.0.0-    | LeSymbolBaseStrokeColor Color-      -- ^ The stroke color for legend symbols. This is only applied if-      --   there is no \"fill\" scale color encoding for the legend.-      ---      --   @since 0.4.0.0-    | LeSymbolDash [Double]-      -- ^ The pattern for dashed symbol strokes (alternating-      --   stroke, space lengths in pixels).-      ---      --   @since 0.4.0.0-    | LeSymbolDashOffset Double-      -- ^ The offset at which to start deawing the symbol dash pattern,-      --   in pixels.-      ---      --   @since 0.4.0.0-    | LeSymbolDirection Orientation-      -- ^ The default direction for symbol legends.-      ---      --   @since 0.4.0.0-    | LeSymbolFillColor Color-      -- ^ The color of the legend symbol.-      ---      --   @since 0.4.0.0-    | LeSymbolOffset Double-      -- ^ The horizontal pixel offset for legend symbols.-      ---      --   @since 0.4.0.0-    | LeSymbolOpacity Opacity-      -- ^ The opacity of the legend symbols.-      ---      --   @since 0.4.0.0-    | LeSymbolSize Double-      -- ^ The size of the legend symbol, in pixels.-    | LeSymbolStrokeColor Color-      -- ^ The stroke color for legend symbols.-      ---      --   @since 0.4.0.0-    | LeSymbolStrokeWidth Double-      -- ^ The width of the symbol's stroke.-    | LeSymbolType Symbol-      -- ^ The default shape type for legend symbols.-    | LeTitle T.Text-      -- ^ The legend title.-      ---      --   @since 0.4.0.0-    | LeNoTitle-      -- ^ Draw no title for the legend.-      ---      --   @since 0.4.0.0-    | LeTitleAlign HAlign-      -- ^ The horizontal text alignment for legend titles.-    | LeTitleAnchor APosition-      -- ^ The text anchor position for legend titles.-      ---      --   @since 0.4.0.0-    | LeTitleBaseline VAlign-      -- ^ The vertical text alignment for legend titles.-    | LeTitleColor Color-      -- ^ The color of the legend title.-    | LeTitleFont T.Text-      -- ^ The font of the legend title.-    | LeTitleFontSize Double-      -- ^ The font size of the legend title.-    | LeTitleFontStyle T.Text-      -- ^ The font style for the legend title.-      ---      --   @since 0.4.0.0-    | LeTitleFontWeight FontWeight-      -- ^ The font weight of the legend title.-    | LeTitleLimit Double-      -- ^ The maxmimum pixel width of the legend title.-    | LeTitleOpacity Opacity-      -- ^ The opacity of the legend title.-      ---      --   @since 0.4.0.0-    | LeTitleOrient Side-      -- ^ The orientation of the legend title.-      ---      --   @since 0.4.0.0-    | LeTitlePadding Double-      -- ^ The padding, in pixels, between title and legend.---legendConfigProperty :: LegendConfig -> LabelledSpec-legendConfigProperty (LeClipHeight x) = "clipHeight" .= x-legendConfigProperty (LeColumnPadding x) = "columnPadding" .= x-legendConfigProperty (LeColumns n) = "columns" .= n-legendConfigProperty (LeCornerRadius x) = "cornerRadius" .= x-legendConfigProperty (LeFillColor s) = "fillColor" .= s-legendConfigProperty (LeGradientDirection o) = "gradientDirection" .= orientationSpec o-legendConfigProperty (LeGradientHorizontalMaxLength x) = "gradientHorizontalMaxLength" .= x-legendConfigProperty (LeGradientHorizontalMinLength x) = "gradientHorizontalMinLength" .= x-legendConfigProperty (LeGradientLabelLimit x) = "gradientLabelLimit" .= x-legendConfigProperty (LeGradientLabelOffset x) = "gradientLabelOffset" .= x-legendConfigProperty (LeGradientLength x) = "gradientLength" .= x-legendConfigProperty (LeGradientOpacity x) = "gradientOpacity" .= x-legendConfigProperty (LeGradientStrokeColor s) = "gradientStrokeColor" .= s-legendConfigProperty (LeGradientStrokeWidth x) = "gradientStrokeWidth" .= x-legendConfigProperty (LeGradientThickness x) = "gradientThickness" .= x-legendConfigProperty (LeGradientVerticalMaxLength x) = "gradientVerticalMaxLength" .= x-legendConfigProperty (LeGradientVerticalMinLength x) = "gradientVerticalMinLength" .= x-legendConfigProperty (LeGridAlign ga) = "gridAlign" .= compositionAlignmentSpec ga-legendConfigProperty (LeLabelAlign ha) = "labelAlign" .= hAlignLabel ha-legendConfigProperty (LeLabelBaseline va) = "labelBaseline" .= vAlignLabel va-legendConfigProperty (LeLabelColor s) = "labelColor" .= s-legendConfigProperty (LeLabelFont s) = "labelFont" .= s-legendConfigProperty (LeLabelFontSize x) = "labelFontSize" .= x-legendConfigProperty (LeLabelFontStyle s) = "labelFontStyle" .= s-legendConfigProperty (LeLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw-legendConfigProperty (LeLabelLimit x) = "labelLimit" .= x-legendConfigProperty (LeLabelOffset x) = "labelOffset" .= x-legendConfigProperty (LeLabelOpacity x) = "labelOapcity" .= x-legendConfigProperty (LeLabelOverlap olap) = "labelOverlap" .= overlapStrategyLabel olap-legendConfigProperty (LeLabelPadding x) = "labelPadding" .= x-legendConfigProperty (LeLabelSeparation x) = "labelSeparation" .= x-legendConfigProperty (LeLayout ll) = "layout" .= object (map legendLayoutSpec ll)-legendConfigProperty (LeLeX x) = "legendX" .= x-legendConfigProperty (LeLeY x) = "legendY" .= x-legendConfigProperty (LeOffset x) = "offset" .= x-legendConfigProperty (LeOrient orl) = "orient" .= legendOrientLabel orl-legendConfigProperty (LePadding x) = "padding" .= x-legendConfigProperty (LeRowPadding x) = "rowPadding" .= x-legendConfigProperty (LeShortTimeLabels b) = "shortTimeLabels" .= b-legendConfigProperty (LeStrokeColor s) = "strokeColor" .= s-legendConfigProperty (LeStrokeDash xs) = "strokeDash" .= xs-legendConfigProperty (LeStrokeWidth x) = "strokeWidth" .= x-legendConfigProperty (LeSymbolBaseFillColor s) = "symbolBaseFillColor" .= s-legendConfigProperty (LeSymbolBaseStrokeColor s) = "symbolBaseStrokeColor" .= s-legendConfigProperty (LeSymbolDash xs) = "symbolDash" .= xs-legendConfigProperty (LeSymbolDashOffset x) = "symbolDashOffset" .= x-legendConfigProperty (LeSymbolDirection o) = "symbolDirection" .= orientationSpec o-legendConfigProperty (LeSymbolFillColor s) = "symbolFillColor" .= s-legendConfigProperty (LeSymbolOffset x) = "symbolOffset" .= x-legendConfigProperty (LeSymbolOpacity x) = "symbolOpacity" .= x-legendConfigProperty (LeSymbolSize x) = "symbolSize" .= x-legendConfigProperty (LeSymbolStrokeColor s) = "symbolStrokeColor" .= s-legendConfigProperty (LeSymbolStrokeWidth x) = "symbolStrokeWidth" .= x-legendConfigProperty (LeSymbolType s) = "symbolType" .= symbolLabel s-legendConfigProperty (LeTitle s) = "title" .= s-legendConfigProperty LeNoTitle = "title" .= A.Null-legendConfigProperty (LeTitleAlign ha) = "titleAlign" .= hAlignLabel ha-legendConfigProperty (LeTitleAnchor anc) = "titleAnchor" .= anchorLabel anc-legendConfigProperty (LeTitleBaseline va) = "titleBaseline" .= vAlignLabel va-legendConfigProperty (LeTitleColor s) = "titleColor" .= s-legendConfigProperty (LeTitleFont s) = "titleFont" .= s-legendConfigProperty (LeTitleFontSize x) = "titleFontSize" .= x-legendConfigProperty (LeTitleFontStyle s) = "titleFontStyle" .= s-legendConfigProperty (LeTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw-legendConfigProperty (LeTitleLimit x) = "titleLimit" .= x-legendConfigProperty (LeTitleOpacity x) = "titleOpacity" .= x-legendConfigProperty (LeTitleOrient orient) = "titleOrient" .= sideLabel orient-legendConfigProperty (LeTitlePadding x) = "titlePadding" .= x---{-|--Indicates the legend orientation. See the-<https://vega.github.io/vega-lite/docs/legend.html#config Vega-Lite documentation>-for more details.---}---- based on schema 3.3.0 #/definitions/LegendOrient--data LegendOrientation-  = LONone-  | LOLeft-  | LORight-  | LOTop-  -- ^ @since 0.4.0.0-  | LOBottom-  -- ^ @since 0.4.0.0-  | LOTopLeft-  | LOTopRight-  | LOBottomLeft-  | LOBottomRight---legendOrientLabel :: LegendOrientation -> T.Text-legendOrientLabel LONone = "none"-legendOrientLabel LOLeft = "left"-legendOrientLabel LORight = "right"-legendOrientLabel LOTop = "top"-legendOrientLabel LOBottom = "bottom"-legendOrientLabel LOTopLeft = "top-left"-legendOrientLabel LOTopRight = "top-right"-legendOrientLabel LOBottomLeft = "bottom-left"-legendOrientLabel LOBottomRight = "bottom-right"---{- |--/Highly experimental/ and used with 'LeLayout'.--@since 0.4.0.0---}---- based on schema 3.3.0 #/definitions/LegendLayout---- TODO: support SignalRef?--data LegendLayout-  = LeLAnchor APosition-    -- ^ The anchor point for legend orient group layout.-  | LeLBottom [BaseLegendLayout]-  | LeLBottomLeft [BaseLegendLayout]-  | LeLBottomRight [BaseLegendLayout]-  | LeLBounds Bounds-    -- ^ The bounds calculation to use for legend orient group layout.-  | LeLCenter Bool-    -- ^ A flag to center legends within a shared orient group.-  | LeLDirection Orientation-    -- ^ The layout firection for legend orient group layout.-  | LeLLeft [BaseLegendLayout]-  | LeLMargin Double-    -- ^ The margin, in pixels, between legends within an orient group.-  | LeLOffset Double-    -- ^ The offset, in pixels, from the chart body for a legend orient group.-  | LeLRight [BaseLegendLayout]-  | LeLTop [BaseLegendLayout]-  | LeLTopLeft [BaseLegendLayout]-  | LeLTopRight [BaseLegendLayout]---legendLayoutSpec :: LegendLayout -> LabelledSpec-legendLayoutSpec (LeLAnchor anc) = "anchor" .= anchorLabel anc-legendLayoutSpec (LeLBottom bl) = "bottom" .= toBLSpec bl-legendLayoutSpec (LeLBottomLeft bl) = "bottom-left" .= toBLSpec bl-legendLayoutSpec (LeLBottomRight bl) = "bottom-right" .= toBLSpec bl-legendLayoutSpec (LeLBounds bnds) = "bounds" .= boundsSpec bnds-legendLayoutSpec (LeLCenter b) = "center" .= b-legendLayoutSpec (LeLDirection o) = "direction" .= orientationSpec o-legendLayoutSpec (LeLLeft bl) = "left" .= toBLSpec bl-legendLayoutSpec (LeLMargin x) = "margin" .= x-legendLayoutSpec (LeLOffset x) = "offset" .= x-legendLayoutSpec (LeLRight bl) = "right" .= toBLSpec bl-legendLayoutSpec (LeLTop bl) = "top" .= toBLSpec bl-legendLayoutSpec (LeLTopLeft bl) = "top-left" .= toBLSpec bl-legendLayoutSpec (LeLTopRight bl) = "top-right" .= toBLSpec bl---toBLSpec :: [BaseLegendLayout] -> VLSpec-toBLSpec = object . map baseLegendLayoutSpec--{- |--/Highly experimental/ and used with constructors from 'LegendLayout'.--@since 0.4.0.0---}---- based on schema 3.3.0 #/definitions/BaseLegendLayout--data BaseLegendLayout-  = BLeLAnchor APosition-    -- ^ The anchor point for legend orient group layout.-  | BLeLBounds Bounds-    -- ^ The bounds calculation to use for legend orient group layout.-  | BLeLCenter Bool-    -- ^ A flag to center legends within a shared orient group.-  | BLeLDirection Orientation-    -- ^ The layout direction for legend orient group layout.-  | BLeLMargin Double-    -- ^ The margin, in pixels, between legends within an orient group.-  | BLeLOffset Double-    -- ^ The offset, in pixels, from the chart body for a legend orient group.---baseLegendLayoutSpec :: BaseLegendLayout -> LabelledSpec-baseLegendLayoutSpec (BLeLAnchor anc) = "anchor" .= anchorLabel anc-baseLegendLayoutSpec (BLeLBounds bnds) = "bounds" .= boundsSpec bnds-baseLegendLayoutSpec (BLeLCenter b) = "center" .= b-baseLegendLayoutSpec (BLeLDirection o) = "direction" .= orientationSpec o-baseLegendLayoutSpec (BLeLMargin x) = "margin" .= x-baseLegendLayoutSpec (BLeLOffset x) = "offset" .= x---{-|--Legend properties, set with 'MLegend'. For more detail see the-<https://vega.github.io/vega-lite/docs/legend.html#legend-properties Vega-Lite documentation>.--The @LEntryPadding@ constructor was removed in @0.4.0.0@.---}--data LegendProperty-    = LClipHeight Double-      -- ^ The height, in pixels, to clip symbol legend entries.-      ---      --   @since 0.4.0.0-    | LColumnPadding Double-      -- ^ The horizontal padding, in pixels, between symbol legend entries.-      ---      --   @since 0.4.0.0-    | LColumns Int-      -- ^ The number of columns in which to arrange symbol legend entries.-      --   A value of @0@ or lower indicates a single row with one column per entry.-      ---      --   @since 0.4.0.0-    | LCornerRadius Double-      -- ^ The corner radius for the full legend.-      ---      --   @since 0.4.0.0-    | LDirection Orientation-      -- ^ The direction of the legend.-      ---      --   @since 0.4.0.0-    | LFillColor Color-      -- ^ The background fill color for the full legend.-      ---      --   @since 0.4.0.0-    | LFormat T.Text-      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html) for-      --   legend values. To distinguish between formatting as numeric values-      --   and data/time values, additionally use 'LFormatAsNum' or 'LFormatAsTemporal'.-    | LFormatAsNum-      -- ^ Legends should be formatted as numbers. Use a-      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)-      --   with 'LFormat'.-      ---      -- @since 0.4.0.0-    | LFormatAsTemporal-      -- ^ Legends should be formatted as dates or times. Use a-      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)-      --   with 'LFormat'.-      ---      -- @since 0.4.0.0-    | LGradientLength Double-      -- ^ The length in pixels of the primary axis of the color gradient.-      ---      --   @since 0.4.0.0-    | LGradientOpacity Opacity-      -- ^ The opacity of the color gradient.-      ---      --   @since 0.4.0.0-    | LGradientStrokeColor Color-      -- ^ The color of the gradient stroke.-      ---      --   @since 0.4.0.0-    | LGradientStrokeWidth Double-      -- ^ The width, in pixels, of the gradient stroke.-      ---      --   @since 0.4.0.0-    | LGradientThickness Double-      -- ^ The thickness, in pixels, of the color gradient.-      ---      --   @since 0.4.0.0-    | LGridAlign CompositionAlignment-      -- ^ The [grid layout](https://vega.github.io/vega/docs/layout) for-      --   the symbol legends.-      ---      --   @since 0.4.0.0-    | LLabelAlign HAlign-      -- ^ @since 0.4.0.0-    | LLabelBaseline VAlign-      -- ^ @since 0.4.0.0-    | LLabelColor Color-      -- ^ @since 0.4.0.0-    | LLabelFont T.Text-      -- ^ @since 0.4.0.0-    | LLabelFontSize Double-      -- ^ @since 0.4.0.0-    | LLabelFontStyle T.Text-      -- ^ @since 0.4.0.0-    | LLabelFontWeight FontWeight-      -- ^ @since 0.4.0.0-    | LLabelLimit Double-      -- ^ @since 0.4.0.0-    | LLabelOffset Double-      -- ^ @since 0.4.0.0-    | LLabelOpacity Opacity-      -- ^ @since 0.4.0.0-    | LLabelOverlap OverlapStrategy-      -- ^ @since 0.4.0.0-    | LLabelPadding Double-      -- ^ @since 0.4.0.0-    | LLabelSeparation Double-      -- ^ @since 0.4.0.0-    | LOffset Double-      -- ^ The offset in pixels by which to displace the legend from-      --   the data rectangle and axes.-    | LOrient LegendOrientation-      -- ^ The legend orientation.-    | LPadding Double-      -- ^ The padding, in pixels, between the border and content of-      --   the legend group.-    | LRowPadding Double-      -- ^ The vertical padding, in pixels, between symbol legend entries.-      ---      --   @since 0.4.0.0-    | LStrokeColor Color-      -- ^ The border stroke color for the full legend.-      ---      --   @since 0.4.0.0-    | LSymbolDash [Double]-      -- ^ The dash style for symbols (alternating stroke, space lengths-      --   in pixels).-      ---      --   @since 0.4.0.0-    | LSymbolDashOffset Double-      -- ^ The pixel offset at which to start drawing the symbol dash array.-      ---      --   @since 0.4.0.0-    | LSymbolFillColor Color-      -- ^ The fill color of the legend symbol.-      ---      --   @since 0.4.0.0-    | LSymbolOffset Double-      -- ^ The horizontal pixel offset for legend symbols.-      ---      --   @since 0.4.0.0-    | LSymbolOpacity Opacity-      -- ^ The opacity of the legend symbols.-      ---      --   @since 0.4.0.0-    | LSymbolSize Double-      -- ^ The size of the legend symbol, in pixels.-      ---      --   @since 0.4.0.0-    | LSymbolStrokeColor Color-      -- ^ The edge color of the legend symbol.-      ---      --   @since 0.4.0.0-    | LSymbolStrokeWidth Double-      -- ^ The width of the sumbol's stroke.-      ---      --   @since 0.4.0.0-    | LSymbolType Symbol-      -- ^ @since 0.4.0.0-    | LTickCount Double-      -- ^ The desired number of tick values for quantitative legends.-    | LTickMinStep Double-      -- ^ The minimum desired step between legend ticks, in terms of the scale-      --   domain values.-      ---      --   @since 0.4.0.0-    | LTitle T.Text-    | LNoTitle-      -- ^ Draw no title.-      ---      -- @since 0.4.0.0-    | LTitleAlign HAlign-      -- ^ @since 0.4.0.0-    | LTitleAnchor APosition-      -- ^ @since 0.4.0.0-    | LTitleBaseline VAlign-      -- ^ @since 0.4.0.0-    | LTitleColor Color-      -- ^ @since 0.4.0.0-    | LTitleFont T.Text-      -- ^ @since 0.4.0.0-    | LTitleFontSize Double-      -- ^ @since 0.4.0.0-    | LTitleFontStyle T.Text-      -- ^ @since 0.4.0.0-    | LTitleFontWeight FontWeight-      -- ^ @since 0.4.0.0-    | LTitleLimit Double-      -- ^ The maximum allowed pixel width of the legend title.-      ---      --   @since 0.4.0.0-    | LTitleOpacity Opacity-      -- ^ Opacity of the legend title.-      ---      --   @since 0.4.0.0-    | LTitleOrient Side-      -- ^ Orientation of the legend title.-      ---      --   @since 0.4.0.0-    | LTitlePadding Double-      -- ^ The padding, in pixels, between title and legend.-      ---      --   @since 0.4.0.0-    | LType LegendType-      -- ^ The type of the legend.-    | LValues LegendValues-      -- ^ Explicitly set the visible legend values.-    | LeX Double-      -- ^ Custom x position, in pixels, for the legend when 'LOrient' is set to 'LONone'.-      ---      --   @since 0.4.0.0-    | LeY Double-      -- ^ Custom y position, in pixels, for the legend when 'LOrient' is set to 'LONone'.-      ---      --   @since 0.4.0.0-    | LZIndex ZIndex-      -- ^ The z-index at which to draw the legend.--legendProperty :: LegendProperty -> LabelledSpec-legendProperty (LClipHeight x) = "clipHeight" .= x-legendProperty (LColumnPadding x) = "columnPadding" .= x-legendProperty (LColumns n) = "columns" .= n-legendProperty (LCornerRadius x) = "cornerRadius" .= x-legendProperty (LDirection o) = "direction" .= orientationSpec o-legendProperty (LFillColor s) = "fillColor" .= s-legendProperty (LFormat s) = "format" .= s-legendProperty LFormatAsNum = "formatType" .= fromT "number"-legendProperty LFormatAsTemporal = "formatType" .= fromT "time"-legendProperty (LGradientLength x) = "gradientLength" .= x-legendProperty (LGradientOpacity x) = "gradientOpacity" .= x-legendProperty (LGradientStrokeColor s) = "gradientStrokeColor" .= s-legendProperty (LGradientStrokeWidth x) = "gradientStrokeWidth" .= x-legendProperty (LGradientThickness x) = "gradientThickness" .= x-legendProperty (LGridAlign ga) = "gridAlign" .= compositionAlignmentSpec ga-legendProperty (LLabelAlign ha) = "labelAlign" .= hAlignLabel ha-legendProperty (LLabelBaseline va) = "labelBaseline" .= vAlignLabel va-legendProperty (LLabelColor s) = "labelColor" .= s-legendProperty (LLabelFont s) = "labelFont" .= s-legendProperty (LLabelFontSize x) = "labelFontSize" .= x-legendProperty (LLabelFontStyle s) = "labelFontStyle" .= s-legendProperty (LLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw-legendProperty (LLabelLimit x) = "labelLimit" .= x-legendProperty (LLabelOffset x) = "labelOffset" .= x-legendProperty (LLabelOpacity x) = "labelOpacity" .= x-legendProperty (LLabelOverlap strat) = "labelOverlap" .= overlapStrategyLabel strat-legendProperty (LLabelPadding x) = "labelPadding" .= x-legendProperty (LLabelSeparation x) = "labelSeparation" .= x-legendProperty (LOffset x) = "offset" .= x-legendProperty (LOrient orl) = "orient" .= legendOrientLabel orl-legendProperty (LPadding x) = "padding" .= x-legendProperty (LRowPadding x) = "rowPadding" .= x-legendProperty (LStrokeColor s) = "strokeColor" .= s--legendProperty (LSymbolDash ds) = "symbolDash" .= ds-legendProperty (LSymbolDashOffset x) = "symbolDashOffset" .= x-legendProperty (LSymbolFillColor s) = "symbolFillColor" .= s-legendProperty (LSymbolOffset x) = "symbolOffset" .= x-legendProperty (LSymbolOpacity x) = "symbolOpacity" .= x-legendProperty (LSymbolSize x) = "symbolSize" .= x-legendProperty (LSymbolStrokeColor s) = "symbolStrokeColor" .= s-legendProperty (LSymbolStrokeWidth x) = "symbolStrikeWidth" .= x-legendProperty (LSymbolType sym) = "symbolType" .= symbolLabel sym-legendProperty (LTickCount x) = "tickCount" .= x-legendProperty (LTickMinStep x) = "tickMinStep" .= x-legendProperty (LTitle s) = "title" .= s-legendProperty LNoTitle = "title" .= A.Null-legendProperty (LTitleAlign ha) = "titleAlign" .= hAlignLabel ha-legendProperty (LTitleAnchor anc) = "titleAnchor" .= anchorLabel anc-legendProperty (LTitleBaseline va) = "titleBaseline" .= vAlignLabel va-legendProperty (LTitleColor s) = "titleColor" .= s-legendProperty (LTitleFont s) = "titleFont" .= s-legendProperty (LTitleFontSize x) = "titleFontSize" .= x-legendProperty (LTitleFontStyle s) = "titleFontStyle" .= s-legendProperty (LTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw-legendProperty (LTitleLimit x) = "titleLimit" .= x-legendProperty (LTitleOpacity x) = "titleOpacity" .= x-legendProperty (LTitleOrient orient) = "titleOrient" .= sideLabel orient-legendProperty (LTitlePadding x) = "titlePadding" .= x-legendProperty (LType lType) = "type" .= legendLabel lType-legendProperty (LValues vals) =-  let ls = case vals of-        LNumbers xs    -> map toJSON xs-        LDateTimes dts -> map (object . map dateTimeProperty) dts-        LStrings ss    -> map toJSON ss-  in "values" .= ls-legendProperty (LeX x) = "legendX" .= x-legendProperty (LeY x) = "legendY" .= x-legendProperty (LZIndex z) = "zindex" .= z----- | A list of data values suitable for setting legend values, used with---   'LValues'.---data LegendValues-    = LDateTimes [[DateTime]]-    | LNumbers [Double]-    | LStrings [T.Text]----- | Specify the padding dimensions in pixel units.--data Padding-    = PSize Double-      -- ^ Use the same padding on all four edges of the container.-    | PEdges Double Double Double Double-      -- ^ Specify the padding for the left, top, right, and bottom edges.---paddingSpec :: Padding -> VLSpec-paddingSpec (PSize p) = toJSON p-paddingSpec (PEdges l t r b) =-  object [ "left" .= l-         , "top" .= t-         , "right" .= r-         , "bottom" .= b-         ]----- | The properties of a point marker on a line or area mark.---   For use with 'MPoint'.------   @since 0.4.0.0--data PointMarker-    = PMTransparent-    -- ^ A transparent marker is used, which can be useful for-    --   interactive selections.-    | PMNone-    -- ^ No marker to be shown.-    | PMMarker [MarkProperty]-    -- ^ The properties of the marks to be shown at the points.-    ---    --   Use an empty list to use a filled point with default properties.---- An empty object has the same meaning as true, so there is no real need to--- treat 'PMMarker []' specially, but I don't think it complicates things--- here.----pointMarkerSpec :: PointMarker -> VLSpec-pointMarkerSpec PMTransparent = "transparent"-pointMarkerSpec PMNone = toJSON False-pointMarkerSpec (PMMarker []) = toJSON True-pointMarkerSpec (PMMarker mps) = object (map markProperty mps)---{-|--Types of geographic map projection. These are based on a subset of those provided-by the <https://github.com/d3/d3-geo d3-geo library>. For details of available-projections see the-<https://vega.github.io/vega-lite/docs/projection.html#projection-types Vega-Lite documentation>.--}---- based on schema 3.3.0 #/definitions/ProjectionType--data Projection-    = Albers-      -- ^ An Albers equal-area conic map projection.-    | AlbersUsa-      -- ^ An Albers USA map projection that combines continental USA with-      --   Alaska and Hawaii. Unlike other projection types, this remains-      --   unaffected by 'PrRotate'.-    | AzimuthalEqualArea-      -- ^ An azimuthal equal area map projection.-    | AzimuthalEquidistant-      -- ^ An azimuthal equidistant map projection.-    | ConicConformal-      -- ^ A conformal conic map projection.-    | ConicEqualArea-      -- ^ An equal area conic map projection.-    | ConicEquidistant-      -- ^ An equidistant conic map projection.-    | Custom T.Text-      -- ^ Specify the name of the custom D3 prohection to use. See the-      --   <https://vega.github.io/vega/docs/projections/#register Vega API>-      --   for more information.-      ---      --   An example: @Custom "winkle3"@-    | Equirectangular-      -- ^ An equirectangular map projection that maps longitude to x and latitude to y.-      --   While showing less area distortion towards the poles than the default 'Mercator'-      --   projection, it is neither equal-area nor conformal.-    | Gnomonic-      -- ^ A gnomonic map projection.-    | Identity-      -- ^ The identiy projection. This can be combined with 'PrReflectX' and-      --   'PrReflectY' in the list of projection properties.-      ---      --   @since 0.4.0.0-    | Mercator-      -- ^ A Mercator map projection. This is the default projection of longitude, latitude-      --   values if no projection is set explicitly. It preserves shape (local angle) and-      --   lines of equal angular bearing remain parallel straight lines. The area is-      --   /significantly/ enlarged towards the poles.-    | Orthographic-      -- ^ An orthographic map projection.-    | Stereographic-      -- ^ A stereographic map projection.-    | TransverseMercator-      -- ^ A transverse Mercator map projection.---projectionLabel :: Projection -> T.Text-projectionLabel Albers = "albers"-projectionLabel AlbersUsa = "albersUsa"-projectionLabel AzimuthalEqualArea = "azimuthalEqualArea"-projectionLabel AzimuthalEquidistant = "azimuthalEquidistant"-projectionLabel ConicConformal = "conicConformal"-projectionLabel ConicEqualArea = "conicEqualarea"-projectionLabel ConicEquidistant = "conicEquidistant"-projectionLabel (Custom pName) = pName-projectionLabel Equirectangular = "equirectangular"-projectionLabel Gnomonic = "gnomonic"-projectionLabel Identity = "identity"-projectionLabel Mercator = "mercator"-projectionLabel Orthographic = "orthographic"-projectionLabel Stereographic = "stereographic"-projectionLabel TransverseMercator = "transverseMercator"----- | Specifies a clipping rectangle for defining---   the clip extent of a map projection.--data ClipRect-    = NoClip-      -- ^ No clipping it to be applied.-    | LTRB Double Double Double Double-      -- ^ The left, top, right, and bottom extents, in pixels,-      --   of a rectangular clip.----- | Specifies the alignment of compositions. It is used with:---   'align', 'alignRC', 'LeGridAlign', and 'LGridAlign'.------   @since 0.4.0.0--data CompositionAlignment-    = CANone-    -- ^ Flow layout is used, where adjacent subviews are placed one after-    --   another.-    | CAEach-    -- ^ Each row and column may be of a variable size.-    | CAAll-    -- ^ All the rows and columns are of the same size (this is based on the-    --   maximum subview size).---compositionAlignmentSpec :: CompositionAlignment -> VLSpec-compositionAlignmentSpec CANone = "none"-compositionAlignmentSpec CAEach = "each"-compositionAlignmentSpec CAAll = "all"---{-|--Properties for customising a geospatial projection that converts longitude,latitude-pairs into planar @(x,y)@ coordinate pairs for rendering and query. For details see the-<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.--This type has been changed in the @0.4.0.0@ release so that all constructors-start with @Pr@ rather than @P@ (and so provide some differentiation to the-'PositionChannel' constructors).---}---- based on schema 3.3.0 #/definitions/Projection--data ProjectionProperty-    = PrType Projection-      -- ^ The type of the map projection.-    | PrClipAngle (Maybe Double)-      -- ^ The clipping circle angle in degrees. A value of @Nothing@ will switch to-      --   antimeridian cutting rather than small-circle clipping.-    | PrClipExtent ClipRect-      -- ^ Projection’s viewport clip extent to the specified bounds in pixels.-    | PrCenter Double Double-      -- ^ Projection’s center as longitude and latitude in degrees.-    | PrScale Double-      -- ^ The projection's zoom scale, which if set, overrides automatic scaling of a-      --   geo feature to fit within the viewing area.-      ---      --   @since 0.4.0.0-    | PrTranslate Double Double-      -- ^ A projection’s panning translation, which if set, overrides automatic positioning-      --   of a geo feature to fit within the viewing area-      ---      --   Note that the prefix is @Pr@ and not @P@, to match the Elm API.-      ---      --   @since 0.4.0.0-    | PrRotate Double Double Double-      -- ^ A projection’s three-axis rotation angle. The order is @lambda@ @phi@ @gamma@,-      --   and specifies the rotation angles in degrees about each spherical axis.-    | PrPrecision Double-      -- ^ Threshold for the projection’s adaptive resampling in pixels, and corresponds to the-      --   Douglas–Peucker distance. If precision is not specified, the projection’s current-      --   resampling precision of 0.707 is used.-      ---      --   Version 3.3.0 of the Vega-Lite spec claims this should be output as a string,-      --   but it is written out as a number since the-      --   [spec is in error](https://github.com/vega/vega-lite/issues/5190).-    | PrReflectX Bool-      -- ^ Reflect the x-coordinates after performing an identity projection. This-      --   creates a left-right mirror image of the geoshape marks when subject to an-      --   identity projection with 'Identity'.-      ---      -- @since 0.4.0.0-    | PrReflectY Bool-      -- ^ Reflect the y-coordinates after performing an identity projection. This-      --   creates a left-right mirror image of the geoshape marks when subject to an-      --   identity projection with 'Identity'.-      ---      -- @since 0.4.0.0-    | PrCoefficient Double-      -- ^ The @Hammer@ map projection coefficient.-    | PrDistance Double-      -- ^ The @Satellite@ map projection distance.-    | PrFraction Double-      -- ^ The @Bottomley@ map projection fraction.-    | PrLobes Int-      -- ^ Number of lobes in lobed map projections such as the @Berghaus star@.-    | PrParallel Double-      -- ^ Parallel for map projections such as the @Armadillo@.-    | PrRadius Double-      -- ^ Radius value for map projections such as the @Gingery@.-    | PrRatio Double-      -- ^ Ratio value for map projections such as the @Hill@.-    | PrSpacing Double-      -- ^ Spacing value for map projections such as the @Lagrange@.-    | PrTilt Double-      -- ^ @Satellite@ map projection tilt.---projectionProperty :: ProjectionProperty -> LabelledSpec-projectionProperty (PrType proj) = "type" .= projectionLabel proj-projectionProperty (PrClipAngle numOrNull) = "clipAngle" .= maybe A.Null toJSON numOrNull-projectionProperty (PrClipExtent rClip) =-  ("clipExtent", case rClip of-    NoClip -> A.Null-    LTRB l t r b -> toJSON (map toJSON [l, t, r, b])-  )-projectionProperty (PrCenter lon lat) = "center" .= [lon, lat]-projectionProperty (PrScale sc) = "scale" .= sc-projectionProperty (PrTranslate tx ty) = "translate" .= [tx, ty]-projectionProperty (PrRotate lambda phi gamma) = "rotate" .= [lambda, phi, gamma]-projectionProperty (PrPrecision pr) = "precision" .= pr  -- the 3.3.0 spec says this is a string, but that's wrong,  See https://github.com/vega/vega-lite/issues/5190-projectionProperty (PrReflectX b) = "reflectX" .= b-projectionProperty (PrReflectY b) = "reflectY" .= b-projectionProperty (PrCoefficient x) = "coefficient" .= x-projectionProperty (PrDistance x) = "distance" .= x-projectionProperty (PrFraction x) = "fraction" .= x-projectionProperty (PrLobes n) = "lobes" .= n-projectionProperty (PrParallel x) = "parallel" .= x-projectionProperty (PrRadius x) = "radius" .= x-projectionProperty (PrRatio x) = "ratio" .= x-projectionProperty (PrSpacing x) = "spacing" .= x-projectionProperty (PrTilt x) = "tilt" .= x---{-|--Sets the cartographic projection used for geospatial coordinates. A projection-defines the mapping from @(longitude,latitude)@ to an @(x,y)@ plane used for rendering.-This is useful when using the 'Geoshape' mark. For further details see the-<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.--@-'projection' [ 'PrType' 'Orthographic', 'PrRotate' (-40) 0 0 ]-@--}-projection :: [ProjectionProperty] -> PropertySpec-projection pProps = (VLProjection, object (map projectionProperty pProps))---{-|--Properties for customising the colors of a range. The parameter should be a-named color scheme such as @\"accent\"@ or @\"purpleorange-11\"@. For details see the-<https://vega.github.io/vega/docs/schemes/#scheme-properties Vega-Lite documentation>.--}-data RangeConfig-    = RCategory T.Text-    | RDiverging T.Text-    | RHeatmap T.Text-    | ROrdinal T.Text-    | RRamp T.Text-    | RSymbol T.Text---rangeConfigProperty :: RangeConfig -> LabelledSpec-rangeConfigProperty rangeCfg =-  let (l, n) = case rangeCfg of-        RCategory nme -> ("category", nme)-        RDiverging nme -> ("diverging", nme)-        RHeatmap nme -> ("heatmap", nme)-        ROrdinal nme -> ("ordinal", nme)-        RRamp nme -> ("ramp", nme)-        RSymbol nme -> ("symbol", nme)--  in l .= object [schemeProperty n []]---{-|--Scale configuration property. These are used to configure all scales.-For more details see the-<https://vega.github.io/vega-lite/docs/scale.html#scale-config Vega-Lite documentation>.---}--data ScaleConfig-    = SCBandPaddingInner Double-      -- ^ Default inner padding for x and y band-ordinal scales.-    | SCBandPaddingOuter Double-      -- ^ Default outer padding for x and y band-ordinal scales.-    | SCBarBandPaddingInner Double-      -- ^ Default inner padding for x and y band-ordinal scales of 'Bar' marks.-      ---      --   @since 0.4.0.0-    | SCBarBandPaddingOuter Double-      -- ^ Default outer padding for x and y band-ordinal scales of 'Bar' marks.-      ---      --   @since 0.4.0.0-    | SCRectBandPaddingInner Double-      -- ^ Default inner padding for x and y band-ordinal scales of 'Rect' marks.-      ---      --   @since 0.4.0.0-    | SCRectBandPaddingOuter Double-      -- ^ Default outer padding for x and y band-ordinal scales of 'Rect' marks.-      ---      --   @since 0.4.0.0-    | SCClamp Bool-      -- ^ Whether or not by default values that exceed the data domain are clamped to-      --   the min/max range value.-    | SCMaxBandSize Double-      -- ^ Default maximum value for mapping quantitative fields to a bar's-      --   size/bandSize.-    | SCMinBandSize Double-      -- ^ Default minimum value for mapping quantitative fields to a bar's-      --   size/bandSize.-    | SCMaxFontSize Double-      -- ^ Default maximum value for mapping a quantitative field to a text-      --   mark's size.-    | SCMinFontSize Double-      -- ^ Default minimum value for mapping a quantitative field to a text-      --   mark's size.-    | SCMaxOpacity Opacity-      -- ^ Default maximum opacity for mapping a field to opacity.-    | SCMinOpacity Opacity-      -- ^ Default minimum opacity for mapping a field to opacity.-    | SCMaxSize Double-      -- ^ Default maximum size for point-based scales.-    | SCMinSize Double-      -- ^ Default minimum size for point-based scales.-    | SCMaxStrokeWidth Double-      -- ^ Default maximum stroke width for rule, line and trail marks.-    | SCMinStrokeWidth Double-      -- ^ Default minimum stroke width for rule, line and trail marks.-    | SCPointPadding Double-      -- ^ Default padding for point-ordinal scales.-    | SCRangeStep (Maybe Double)-      -- ^ Default range step for band and point scales when the mark is not text.-    | SCRound Bool-      -- ^ Are numeric values are rounded to integers when scaling? Useful-      --   for snapping to the pixel grid.-    | SCTextXRangeStep Double-      -- ^ Default range step for x band and point scales of text marks.-    | SCUseUnaggregatedDomain Bool-      -- ^ Whether or not to use the source data range before aggregation.---scaleConfigProperty :: ScaleConfig -> LabelledSpec-scaleConfigProperty (SCBandPaddingInner x) = "bandPaddingInner" .= x-scaleConfigProperty (SCBandPaddingOuter x) = "bandPaddingOuter" .= x-scaleConfigProperty (SCBarBandPaddingInner x) = "barBandPaddingInner" .= x-scaleConfigProperty (SCBarBandPaddingOuter x) = "barBandPaddingOuter" .= x-scaleConfigProperty (SCRectBandPaddingInner x) = "rectBandPaddingInner" .= x-scaleConfigProperty (SCRectBandPaddingOuter x) = "rectBandPaddingOuter" .= x-scaleConfigProperty (SCClamp b) = "clamp" .= b-scaleConfigProperty (SCMaxBandSize x) = "maxBandSize" .= x-scaleConfigProperty (SCMinBandSize x) = "minBandSize" .= x-scaleConfigProperty (SCMaxFontSize x) = "maxFontSize" .= x-scaleConfigProperty (SCMinFontSize x) = "minFontSize" .= x-scaleConfigProperty (SCMaxOpacity x) = "maxOpacity" .= x-scaleConfigProperty (SCMinOpacity x) = "minOpacity" .= x-scaleConfigProperty (SCMaxSize x) = "maxSize" .= x-scaleConfigProperty (SCMinSize x) = "minSize" .= x-scaleConfigProperty (SCMaxStrokeWidth x) = "maxStrokeWidth" .= x-scaleConfigProperty (SCMinStrokeWidth x) = "minStrokeWidth" .= x-scaleConfigProperty (SCPointPadding x) = "pointPadding" .= x-scaleConfigProperty (SCRangeStep numOrNull) = "rangeStep" .= maybe A.Null toJSON numOrNull-scaleConfigProperty (SCRound b) = "round" .= b-scaleConfigProperty (SCTextXRangeStep x) = "textXRangeStep" .= x-scaleConfigProperty (SCUseUnaggregatedDomain b) = "useUnaggregatedDomain" .= b----- | Indicates the type of selection to be generated by the user.--data Selection-    = Single-      -- ^ Allows one mark at a time to be selected.-    | Multi-      -- ^ Allows multiple items to be selected (e.g. with-      --   shift-click).-    | Interval-      -- ^ Allows a bounding rectangle to be dragged by the user,-      --   selecting all items which intersect it.---selectionLabel :: Selection -> T.Text-selectionLabel Single = "single"-selectionLabel Multi = "multi"-selectionLabel Interval = "interval"---{-|--Properties for customising the nature of the selection. See the-<https://vega.github.io/vega-lite/docs/selection.html#selection-properties Vega-Lite documentation>-for details.--For use with 'select' and 'SelectionStyle'.--}-data SelectionProperty-    = Empty-      -- ^ Make a selection empty by default when nothing selected.-    | BindScales-      -- ^ Enable two-way binding between a selection and the scales used-      --   in the same view. This is commonly used for zooming and panning-      --   by binding selection to position scaling:-      ---      --   @sel = 'selection' . 'select' \"mySelection\" 'Interval' ['BindScales']@-    | On T.Text-      -- ^ [Vega event stream selector](https://vega.github.io/vega/docs/event-streams/#selector)-      --   that triggers a selection, or the empty string (which sets the property to @false@).-    | Clear T.Text-      -- ^ [Vega event stream selector](https://vega.github.io/vega/docs/event-streams/#selector)-      --   that can clear a selection. For example, to allow a zoomed/panned view to be reset-      --   on shift-click:-      ---      -- @-      -- 'selection'-      --     . 'select' \"myZoomPan\"-      --         'Interval'-      --         ['BindScales', 'Clear' \"click[event.shiftKey]\"]-      -- @-      ---      --   To remove the default clearing behaviour of a selection, provide an empty string-      --   rather than an event stream selector.-      ---      --   @since 0.4.0.0-    | Translate T.Text-      -- ^ Translation selection transformation used for panning a view. See the-      --   [Vega-Lite translate documentation](https://vega.github.io/vega-lite/docs/translate.html).-    | Zoom T.Text-      -- ^ Zooming selection transformation used for zooming a view. See the-      --   [Vega-Lite zoom documentation](https://vega.github.io/vega-lite/docs/zoom.html).-    | Fields [T.Text]-      -- ^ Field names for projecting a selection.-    | Encodings [Channel]-      -- ^ Encoding channels that form a named selection.-      ---      --   For example, to __project__ a selection across all items that-      --   share the same value in the color channel:-      ---      --   @sel = 'selection' . 'select' \"mySelection\" 'Multi' ['Encodings' ['ChColor']]@-    | SInit [(T.Text, DataValue)]-      -- ^ Initialise one or more selections with values from bound fields.-      --   See also 'SInitInterval'.-      ---      --   For example,-      ---      --   @-      --   'selection'-      --       . 'select' \"CylYr\"-      --           'Single'-      --           [ 'Fields' [\"Cylinders\", \"Year\"]-      --           , 'SInit'-      --               [ (\"Cylinders\", 'Number' 4)-      --               , (\"Year\", 'Number' 1977)-      --               ]-      --           , 'Bind'-      --               [ 'IRange' \"Cylinders\" ['InMin' 3, 'InMax' 8, 'InStep' 1]-      --               , 'IRange' \"Year\" ['InMin' 1969, 'InMax' 1981, 'InStep' 1]-      --               ]-      --           ]-      --   @-      ---      --   @since 0.4.0.0-    | SInitInterval (Maybe (DataValue, DataValue)) (Maybe (DataValue, DataValue))-      -- ^ Initialize the domain extent of an interval selection. See-      --   also 'SInit'.-      ---      --   The parameters refer to the x and y axes, given in the order-      --   @(minimum, maximum)@ for each axis. If an axis is set to-      --   @Nothing@ then the selection is projected over that-      --   dimension. At least one of the two arguments should be-      --   set (i.e. not @Nothing@).-      ---      --   @-      --   'select' \"mySelection\"-      --          'Interval'-      --          [ 'SInitInterval'-      --              (Just ( 'DateTime' ['DTYear' 2013]-      --                    , 'DateTime' ['DTYear' 2015]-      --                    )-      --              (Just ('Number' 40, 'Number' 80))-      --          ]-      --   @-      ---      --   @since 0.4.0.0-    | ResolveSelections SelectionResolution-      -- ^ Strategy that determines how selections' data queries are resolved when applied-      --   in a filter transform, conditional encoding rule, or scale domain.-    | SelectionMark [SelectionMarkProperty]-      -- ^ Appearance of an interval selection mark (dragged rectangle).-    | Bind [Binding]-      -- ^ Binding to some input elements as part of a named selection.-      ---      --   The followig example allows a selection to be based on a-      --   drop-down list of options:-      ---      --   @-      --   sel = 'selection'-      --           . 'select' \"mySelection\"-      --               'Single'-      --               ['Fields' [\"crimeType\"]-      --               , 'Bind' ['ISelect' \"crimeType\"-      --                         ['InOptions'-      --                            [ \"Anti-social behaviour\"-      --                            , \"Criminal damage and arson\"-      --                            , \"Drugs\"-      --                            , \"Robbery\"-      --                            , \"Vehicle crime\"-      --                            ]-      --                         ]-      --                      ]-      --               ]-      --   @-    | Nearest Bool-      -- ^ Whether or not a selection should capture nearest marks to a pointer-      --   rather than an exact position match.-    | Toggle T.Text-      -- ^ Predicate expression that determines a toggled selection. See the-      --   [Vega-Lite toggle documentation](https://vega.github.io/vega-lite/docs/toggle.html).---selectionProperty :: SelectionProperty -> LabelledSpec-selectionProperty (Fields fNames) = "fields" .= map toJSON fNames-selectionProperty (Encodings channels) = "encodings" .= map (toJSON . channelLabel) channels-selectionProperty (SInit iVals) = "init" .= object (map (second dataValueSpec) iVals)--- This is invalid according to the specification-selectionProperty (SInitInterval Nothing Nothing) = "init" .= A.Null-selectionProperty (SInitInterval mx my) =-  let conv (_, Nothing) = Nothing-      conv (lbl, Just (lo, hi)) = Just (lbl .= [ dataValueSpec lo, dataValueSpec hi ])--  in "init" .= object (mapMaybe conv (zip ["x", "y"] [mx, my]))--selectionProperty (On e) = "on" .= e-selectionProperty (Clear e) = "clear" .= if T.null e then toJSON False else toJSON e-selectionProperty Empty = "empty" .= fromT "none"-selectionProperty (ResolveSelections res) = "resolve" .= selectionResolutionLabel res-selectionProperty (SelectionMark markProps) = "mark" .= object (map selectionMarkProperty markProps)-selectionProperty BindScales = "bind" .= fromT "scales"-selectionProperty (Bind binds) = "bind" .= object (map bindingSpec binds)-selectionProperty (Nearest b) = "nearest" .= b-selectionProperty (Toggle expr) = "toggle" .= expr-selectionProperty (Translate e) = "translate" .= if T.null e then toJSON False else toJSON e-selectionProperty (Zoom e) = "zoom" .= if T.null e then toJSON False else toJSON e----- | Indicates a channel type to be used in a resolution specification.---- assuming this is based on schema 3.3.0 #/definitions/SingleDefUnitChannel--data Channel-    = ChX-    | ChY-    | ChX2-    | ChY2-    | ChLongitude-      -- ^ @since 0.4.0.0-    | ChLongitude2-      -- ^ @since 0.4.0.0-    | ChLatitude-      -- ^ @since 0.4.0.0-    | ChLatitude2-      -- ^ @since 0.4.0.0-    | ChColor-    | ChFill-      -- ^ @since 0.3.0.0-    | ChFillOpacity-      -- ^ @since 0.4.0.0-    | ChHref-      -- ^ @since 0.4.0.0-    | ChKey-      -- ^ @since 0.4.0.0-    | ChStroke-      -- ^ @since 0.3.0.0-    | ChStrokeOpacity-      -- ^ @since 0.4.0.0-    | ChStrokeWidth-      -- ^ @since 0.4.0.0-    | ChOpacity-    | ChShape-    | ChSize-    | ChText-      -- ^ @since 0.4.0.0-    | ChTooltip-      -- ^ @since 0.4.0.0---channelLabel :: Channel -> T.Text-channelLabel ChX = "x"-channelLabel ChY = "y"-channelLabel ChX2 = "x2"-channelLabel ChY2 = "y2"-channelLabel ChLongitude = "longitude"-channelLabel ChLatitude = "latitude"-channelLabel ChLongitude2 = "longitude2"-channelLabel ChLatitude2 = "latitude2"-channelLabel ChColor = "color"-channelLabel ChFill = "fill"-channelLabel ChStroke = "stroke"-channelLabel ChStrokeWidth = "strokeWidth"-channelLabel ChShape = "shape"-channelLabel ChSize = "size"-channelLabel ChFillOpacity = "fillOpacity"-channelLabel ChStrokeOpacity = "strokeOpacity"-channelLabel ChOpacity = "opacity"-channelLabel ChText = "text"-channelLabel ChTooltip = "tooltip"-channelLabel ChHref = "href"-channelLabel ChKey = "key"---{-|--Determines how selections in faceted or repeated views are resolved. See the-<https://vega.github.io/vega-lite/docs/selection.html#resolve Vega-Lite documentation>-for details.--For use with 'ResolveSelections'.---}-data SelectionResolution-    = Global-      -- ^ One selection available across all subviews (default).-    | Union-      -- ^ Each subview contains its own brush and marks are selected if they lie-      --   within /any/ of these individual selections.-    | Intersection-      -- ^  Each subview contains its own brush and marks are selected if they lie-      --    within /all/ of these individual selections.---selectionResolutionLabel :: SelectionResolution -> T.Text-selectionResolutionLabel Global = "global"-selectionResolutionLabel Union = "union"-selectionResolutionLabel Intersection = "intersect"---{-|--Properties for customising the appearance of an interval selection mark (dragged-rectangle). For details see the-<https://vega.github.io/vega-lite/docs/selection.html#interval-mark Vega-Lite documentation>.---}-data SelectionMarkProperty-    = SMFill T.Text-    | SMFillOpacity Opacity-    | SMStroke T.Text-    | SMStrokeOpacity Opacity-    | SMStrokeWidth Double-    | SMStrokeDash [Double]-    | SMStrokeDashOffset Double---selectionMarkProperty :: SelectionMarkProperty -> LabelledSpec-selectionMarkProperty (SMFill colour) = "fill" .= colour-selectionMarkProperty (SMFillOpacity x) = "fillOpacity" .= x-selectionMarkProperty (SMStroke colour) = "stroke" .= colour-selectionMarkProperty (SMStrokeOpacity x) = "strokeOpacity" .= x-selectionMarkProperty (SMStrokeWidth x) = "strokeWidth" .= x-selectionMarkProperty (SMStrokeDash xs) = "strokeDash" .= xs-selectionMarkProperty (SMStrokeDashOffset x) = "strokeDashOffset" .= x---{-|--GUI Input properties. The type of relevant property will depend on the type of-input element selected. For example an @InRange@ (slider) can have numeric min,-max and step values; @InSelect@ (selector) has a list of selection label options.-For details see the-<https://vega.github.io/vega/docs/signals/#bind Vega input element binding documentation>.--The @debounce@ property, available for all input types allows a delay in input event-handling to be added in order to avoid unnecessary event broadcasting. The @Element@-property is an optional CSS selector indicating the parent element to which the-input element should be added. This allows the option of the input element to be-outside the visualization container.--}---- based on schema 3.3.0 #/definitions/BindRange---       or              #/definitions/InputBinding---- placeholder is in InputBinding--- debounce is in BindCheckbox / BindRadioSelect / BindRange / InputBinding--- element is in BindCheckbox / BindRadioSelect / BindRange / InputBinding---- but InputBinding doesn't have min/max/others--data InputProperty-    = Debounce Double-    | Element T.Text-    | InOptions [T.Text]-    | InMin Double-    | InMax Double-    | InName T.Text-    | InStep Double-    | InPlaceholder T.Text---inputProperty :: InputProperty -> LabelledSpec-inputProperty (Debounce x) = "debounce" .= x-inputProperty (Element el) = "element" .= el -- #/definitions/Element-inputProperty (InOptions opts) = "options" .= map toJSON opts-inputProperty (InMin x) = "min" .= x-inputProperty (InMax x) = "max" .= x-inputProperty (InName s) = "name" .= s-inputProperty (InStep x) = "step" .= x-inputProperty (InPlaceholder el) = "placeholder" .= toJSON el---{-|--Describes the binding property of a selection based on some HTML input element-such as a checkbox or radio button. For details see the-<https://vega.github.io/vega-lite/docs/bind.html#scale-binding Vega-Lite documentation>-and the-<https://vega.github.io/vega/docs/signals/#bind Vega input binding documentation>.--}-data Binding-    = IRange T.Text [InputProperty]-      -- ^ Range slider input element that can bound to a named field value.-    | ICheckbox T.Text [InputProperty]-      -- ^ Checkbox input element that can bound to a named field value.-    | IRadio T.Text [InputProperty]-      -- ^ Radio box input element that can bound to a named field value.-    | ISelect T.Text [InputProperty]-      -- ^ Select input element that can bound to a named field value.-    | IText T.Text [InputProperty]-      -- ^ Text input element that can bound to a named field value.-    | INumber T.Text [InputProperty]-      -- ^ Number input element that can bound to a named field value.-    | IDate T.Text [InputProperty]-      -- ^ Date input element that can bound to a named field value.-    | ITime T.Text [InputProperty]-      -- ^ Time input element that can bound to a named field value.-    | IMonth T.Text [InputProperty]-      -- ^ Month input element that can bound to a named field value.-    | IWeek T.Text [InputProperty]-      -- ^ Week input element that can bound to a named field value.-    | IDateTimeLocal T.Text [InputProperty]-      -- ^ Local time input element that can bound to a named field value.-    | ITel T.Text [InputProperty]-      -- ^ Telephone number input element that can bound to a named field value.-    | IColor T.Text [InputProperty]-      -- ^ Color input element that can bound to a named field value.---bindingSpec :: Binding -> LabelledSpec-bindingSpec bnd =-  let (lbl, input, ps) = case bnd of-        IRange label props -> (label, fromT "range", props)-        ICheckbox label props -> (label, "checkbox", props)-        IRadio label props -> (label, "radio", props)-        ISelect label props -> (label, "select", props)-        IText label props -> (label, "text", props)-        INumber label props -> (label, "number", props)-        IDate label props -> (label, "date", props)-        ITime label props -> (label, "time", props)-        IMonth label props -> (label, "month", props)-        IWeek label props -> (label, "week", props)-        IDateTimeLocal label props -> (label, "datetimelocal", props)-        ITel label props -> (label, "tel", props)-        IColor label props -> (label, "color", props)--  in (lbl, object (("input" .= input) : map inputProperty ps))----- | Indicates the anchor position for text.--data APosition-    = AStart-      -- ^ The start of the text.-    | AMiddle-      -- ^ The middle of the text.-    | AEnd-      -- ^ The end of the text.---anchorLabel :: APosition -> T.Text-anchorLabel AStart = "start"-anchorLabel AMiddle = "middle"-anchorLabel AEnd = "end"---{-|--Title configuration properties. These are used to configure the default style-of all titles within a visualization.-For further details see the-<https://vega.github.io/vega-lite/docs/title.html#config Vega-Lite documentation>.--}-data TitleConfig-    = TAnchor APosition-      -- ^ Default anchor position when placing titles.-    | TAngle Angle-      -- ^ Default angle when orientating titles.-    | TBaseline VAlign-      -- ^ Default vertical alignment when placing titles.-    | TColor Color-      -- ^ Default color when showing titles.-    | TFont T.Text-      -- ^ Default font when showing titles.-    | TFontSize Double-      -- ^ Default font size when showing titles.-    | TFontStyle T.Text-      -- ^ Defaylt font style when showing titles.-      ---      --   @since 0.4.0.0-    | TFontWeight FontWeight-      -- ^ Default font weight when showing titles.-    | TFrame TitleFrame-      -- ^ Default title position anchor.-      ---      --   @since 0.4.0.0-    | TLimit Double-      -- ^ Default maximum length, in pixels, of titles.-    | TOffset Double-      -- ^ Default offset, in pixels, of titles relative to the chart body.-    | TOrient Side-      -- ^ Default placement of titles relative to the chart body.-    | TStyle [T.Text]-      -- ^ A list of named styles to apply. A named style can be specified-      --   via 'NamedStyle' or 'NamedStyles'. Later styles in the list will-      --   override earlier ones if there is a conflict in any of the-      --   properties.-      ---      --   @since 0.4.0.0-    | TZIndex ZIndex-      -- ^ Drawing order of a title relative to the other chart elements.-      ---      --   @since 0.4.0.0--titleConfigSpec :: TitleConfig -> LabelledSpec-titleConfigSpec (TAnchor an) = "anchor" .= anchorLabel an-titleConfigSpec (TAngle x) = "angle" .= x-titleConfigSpec (TBaseline va) = "baseline" .= vAlignLabel va-titleConfigSpec (TColor clr) = "color" .= clr-titleConfigSpec (TFont fnt) = "font" .= fnt-titleConfigSpec (TFontSize x) = "fontSize" .= x-titleConfigSpec (TFontStyle s) = "fontStyle" .= s-titleConfigSpec (TFontWeight w) = "fontWeight" .= fontWeightSpec w-titleConfigSpec (TFrame tf) = "frame" .= titleFrameSpec tf-titleConfigSpec (TLimit x) = "limit" .= x-titleConfigSpec (TOffset x) = "offset" .= x-titleConfigSpec (TOrient sd) = "orient" .= sideLabel sd-titleConfigSpec (TStyle [style]) = "style" .= style  -- not really needed-titleConfigSpec (TStyle styles) = "style" .= styles-titleConfigSpec (TZIndex z) = "zindex" .= z---- | Specifies how the title anchor is positioned relative to the frame.------   @since 0.4.0.0-data TitleFrame-    = FrBounds-      -- ^ The position is relative to the full bounding box.-    | FrGroup-      -- ^ The pistion is relative to the group width / height.--titleFrameSpec :: TitleFrame -> VLSpec-titleFrameSpec FrBounds = "bounds"-titleFrameSpec FrGroup = "group"----- | The properties for a single view or layer background.------   @since 0.4.0.0--data ViewBackground-    = VBStyle [T.Text]-    -- ^ A list of named styles to apply. A named style can be specified-    --   via 'NamedStyle' or 'NamedStyles'. Later styles in the list will-    --   override earlier ones if there is a conflict in any of the mark-    --   properties.-    | VBCornerRadius Double-    -- ^ The radius in pixels of rounded corners.-    | VBFill (Maybe T.Text)-    -- ^ Fill color.-    | VBFillOpacity Opacity-    -- ^ Fill opacity.-    | VBOpacity Opacity-    -- ^ Overall opacity.-    | VBStroke (Maybe T.Text)-    -- ^ The stroke color for a line around the background. If @Nothing@ then-    --   no line is drawn.-    | VBStrokeOpacity Opacity-    -- ^ The opacity of the line around the background, if drawn.-    | VBStrokeWidth Double-    -- ^ The width of the line around the background, if drawn.-    | VBStrokeCap StrokeCap-    -- ^ The cap line-ending for the line around the background, if drawn.-    | VBStrokeDash [Double]-    -- ^ The dash style of the line around the background, if drawn.-    | VBStrokeDashOffset Double-    -- ^ The dash offset of the line around the background, if drawn.-    | VBStrokeJoin StrokeJoin-    -- ^ The line-joining style of the line around the background, if drawn.-    | VBStrokeMiterLimit Double-    -- ^ The mitre limit at which to bevel the line around the background, if drawn.---viewBackgroundSpec :: ViewBackground -> LabelledSpec-viewBackgroundSpec (VBStyle [style]) = "style" .= style  -- special case singleton-viewBackgroundSpec (VBStyle styles) = "style" .= styles-viewBackgroundSpec (VBCornerRadius r) = "cornerRadius" .= r-viewBackgroundSpec (VBFill (Just s)) = "fill" .= s-viewBackgroundSpec (VBFill Nothing) = "fill" .= A.Null-viewBackgroundSpec (VBFillOpacity x) = "fillOpacity" .= x-viewBackgroundSpec (VBOpacity x) = "opacity" .= x-viewBackgroundSpec (VBStroke (Just s)) = "stroke" .= s-viewBackgroundSpec (VBStroke Nothing) = "stroke" .= A.Null-viewBackgroundSpec (VBStrokeOpacity x) = "strokeOpacity" .= x-viewBackgroundSpec (VBStrokeCap cap) = "strokeCap" .= strokeCapLabel cap-viewBackgroundSpec (VBStrokeJoin jn) = "strokeJoin" .= strokeJoinLabel jn-viewBackgroundSpec (VBStrokeWidth x) = "strokeWidth" .= x-viewBackgroundSpec (VBStrokeDash xs) = "strokeDash" .= xs-viewBackgroundSpec (VBStrokeDashOffset x) = "strokeDashOffset" .= x-viewBackgroundSpec (VBStrokeMiterLimit x) = "strokeMiterLimit" .= x----- | The background style of a single view or layer in a view composition.------   @since 0.4.0.0--viewBackground :: [ViewBackground] -> PropertySpec-viewBackground vbs = (VLViewBackground, object (map viewBackgroundSpec vbs))---{-|--View configuration property. These are used to configure the style of a single-view within a visualization such as its size and default fill and stroke colors.-For further details see the-<https://vega.github.io/vega-lite/docs/spec.html#config Vega-Lite documentation>.--This type has been changed in the @0.4.0.0@ release to use a consistent-naming scheme for the constructors (everything starts with @View@). Prior to-this release only @ViewWidth@ and @ViewHeight@ were named this way. There-are also five new constructors.---}---- based on schema 3.3.0 #/definitions/ViewConfig--data ViewConfig-    = ViewWidth Double-      -- ^ The default width of the single plot or each plot in a trellis plot when the-      --   visualization has a continuous (non-ordinal) scale or when the-      --   'SRangeStep'/'ScRangeStep' is @Nothing@ for an ordinal scale (x axis).-    | ViewHeight Double-      -- ^ The default height of the single plot or each plot in a trellis plot when the-      --   visualization has a continuous (non-ordinal) scale or when the-      --   'SRangeStep'/'ScRangeStep' is @Nothing@ for an ordinal scale (y axis).-    | ViewClip Bool-      -- ^ Should the view be clipped?-    | ViewCornerRadius Double-      -- ^ The radius, in pixels, of rounded rectangle corners.-      ---      --   The default is @0@.-      ---      --   @since 0.4.0.0-    | ViewFill (Maybe T.Text)-      -- ^ The fill color.-    | ViewFillOpacity Opacity-      -- ^ The fill opacity.-    | ViewOpacity Opacity-      -- ^ The overall opacity.-      ---      --   The default is @0.7@ for non-aggregate plots with 'Point', 'Tick',-      --   'Circle', or 'Square' marks or layered 'Bar' charts, and @1@-      --   otherwise.-      ---      --   @since 0.4.0.0-    | ViewStroke (Maybe T.Text)-      -- ^ The stroke color.-    | ViewStrokeCap StrokeCap-      -- ^ The stroke cap for line-ending style.-      ---      --   @since 0.4.0.0-    | ViewStrokeDash [Double]-      -- ^ The stroke dash style. It is defined by an alternating 'on-off'-      --   sequence of line lengths, in pixels.-    | ViewStrokeDashOffset Double-      -- ^ Number of pixels before the first line dash is drawn.-    | ViewStrokeJoin StrokeJoin-      -- ^ The stroke line-join method.-      ---      --   @since 0.4.0.0-    | ViewStrokeMiterLimit Double-      -- ^ The miter limit at which to bevel a line join.-      ---      --   @since 0.4.0.0-    | ViewStrokeOpacity Opacity-      -- ^ The stroke opacity.-    | ViewStrokeWidth Double-      -- ^ The stroke width, in pixels.---viewConfigProperty :: ViewConfig -> LabelledSpec-viewConfigProperty (ViewWidth x) = "width" .= x-viewConfigProperty (ViewHeight x) = "height" .= x-viewConfigProperty (ViewClip b) = "clip" .= b-viewConfigProperty (ViewCornerRadius x) = "cornerRadius" .= x-viewConfigProperty (ViewFill ms) = "fill" .= maybe A.Null toJSON ms-viewConfigProperty (ViewFillOpacity x) = "fillOpacity" .= x-viewConfigProperty (ViewOpacity x) = "opacity" .= x-viewConfigProperty (ViewStroke ms) = "stroke" .= maybe A.Null toJSON ms-viewConfigProperty (ViewStrokeCap sc) = "strokeCap" .= strokeCapLabel sc-viewConfigProperty (ViewStrokeDash xs) = "strokeDash" .= xs-viewConfigProperty (ViewStrokeDashOffset x) = "strokeDashOffset" .= x-viewConfigProperty (ViewStrokeJoin sj) = "strokeJoin" .= strokeJoinLabel sj-viewConfigProperty (ViewStrokeMiterLimit x) = "strokeMiterLimit" .= x-viewConfigProperty (ViewStrokeOpacity x) = "strokeOpacity" .= x-viewConfigProperty (ViewStrokeWidth x) = "strokeWidth" .= x---{-|--Type of configuration property to customise. See the-<https://vega.github.io/vega-lite/docs/config.html Vega-Lite documentation>-for details.---}---- based on schema 3.3.0 #/definitions/Config------ TODO:---   Bar - change to BarConfig rather than MarkProperty?---     BoxplotStyle BoxPlotConfig---     Concat CompositionConfig---     ErrorBand ErrorBandCOnfig---     ErrorBar ErrorBarCOnfig---   Facet takes CompositionConfig not FacetConfig---     HeaderColumn takes HeaderConfig, just as HeaderStyle does---     HeaderFacet ditto---     HeaderRow ditto---   LineStyle takes LineConfig not MarkConfig---   TextStyle takes TextConfig not MarkConfig---   TickStyle takes TickConfig not MarkConfig---   TrailStyle takes LineConfig not MarkConfig-----data ConfigurationProperty-    = AreaStyle [MarkProperty]-      -- ^ The default appearance of area marks.-    | Autosize [Autosize]-      -- ^ The default sizing of visualizations.-    | Axis [AxisConfig]-      -- ^ The default appearance of axes.-    | AxisBand [AxisConfig]-      -- ^ The default appearance of axes with band scaling.-    | AxisBottom [AxisConfig]-      -- ^ The default appearance of the bottom-side axes.-    | AxisLeft [AxisConfig]-      -- ^ The default appearance of the left-side axes.-    | AxisRight [AxisConfig]-      -- ^ The default appearance of the right-side axes.-    | AxisTop [AxisConfig]-      -- ^ The default appearance of the top-side axes.-    | AxisX [AxisConfig]-      -- ^ The default appearance of the X axes.-    | AxisY [AxisConfig]-      -- ^ The default appearance of the Y axes.-    | Background T.Text-      -- ^ The default background color of visualizations.-    | BarStyle [MarkProperty]-      -- ^ The default appearance of bar marks.-    | CircleStyle [MarkProperty]-      -- ^ The default appearance of circle marks.-    | ConcatStyle [ConcatConfig]-      -- ^ The default appearance of concatenated layouts.-      ---      --   @since 0.4.0.0-    | CountTitle T.Text-      -- ^ The default title style for count fields.-    | FacetStyle [FacetConfig]-      -- ^ The default appearance of facet layouts.-      ---      --   @since 0.4.0.0-    | FieldTitle FieldTitleProperty-      -- ^ The default title-generation style for fields.-    | GeoshapeStyle [MarkProperty]-      -- ^ The default appearance of geoshape marks.-      ---      --   @since 0.4.0.0-    | HeaderStyle [HeaderProperty]-      -- ^ The default appearance of facet headers.-      ---      --   @since 0.4.0.0-    | Legend [LegendConfig]-      -- ^ The default appearance of legends.-    | LineStyle [MarkProperty]-      -- ^ The default appearance of line marks.-    | MarkStyle [MarkProperty]-      -- ^ The default mark appearance.-    | NamedStyle T.Text [MarkProperty]-      -- ^ The default appearance of a single named style.-    | NamedStyles [(T.Text, [MarkProperty])]-      -- ^ The default appearance of a list of named styles.-      ---      --   @since 0.4.0.0-    | NumberFormat T.Text-      -- ^ The default number formatting for axis and text labels.-    | Padding Padding-      -- ^ The default padding in pixels from the edge of the of visualization-      --   to the data rectangle.-    | PointStyle [MarkProperty]-      -- ^ The default appearance of point marks.-    | Projection [ProjectionProperty]-      -- ^ The default style of map projections.-    | Range [RangeConfig]-      -- ^ The default range properties used when scaling.-    | RectStyle [MarkProperty]-      -- ^ The default appearance of rectangle marks.-    | RemoveInvalid Bool-      -- ^ The default handling of invalid (@null@ and @NaN@) values. If @True@,-      --   invalid values are skipped or filtered out when represented as marks.-    | RuleStyle [MarkProperty]-      -- ^ The default appearance of rule marks.-    | Scale [ScaleConfig]   -- TODO: rename ScaleStyle-      -- ^ The default properties used when scaling.-    | SelectionStyle [(Selection, [SelectionProperty])]-      -- ^ The default appearance of selection marks.-    | SquareStyle [MarkProperty]-      -- ^  the default appearance of square marks-    | Stack StackOffset-      -- ^ The default stack offset style for stackable marks.-      ---      --   Changed from @StackProperty@ in version @0.4.0.0@.-    | TextStyle [MarkProperty]-      -- ^ The default appearance of text marks.-    | TickStyle [MarkProperty]-      -- ^ The default appearance of tick marks.-    | TimeFormat T.Text-      -- ^ The default time format for axis and legend labels.-    | TitleStyle [TitleConfig]-      -- ^ The default appearance of visualization titles.-    | TrailStyle [MarkProperty]-      -- ^ The default style of trail marks.-      ---      --   @since 0.4.0.0-    | View [ViewConfig]-      -- ^ The default single view style.--configProperty :: ConfigurationProperty -> LabelledSpec-configProperty (Autosize aus) = "autosize" .= object (map autosizeProperty aus)-configProperty (Background bg) = "background" .= bg-configProperty (CountTitle ttl) = "countTitle" .= ttl-configProperty (ConcatStyle cps) = "concat" .= object (map concatConfigProperty cps)-configProperty (FieldTitle ftp) = "fieldTitle" .= fieldTitleLabel ftp-configProperty (RemoveInvalid b) = "invalidValues" .= if b then "filter" else A.Null-configProperty (NumberFormat fmt) = "numberFormat" .= fmt-configProperty (Padding pad) = "padding" .= paddingSpec pad-configProperty (TimeFormat fmt) = "timeFormat" .= fmt-configProperty (Axis acs) = "axis" .= object (map axisConfigProperty acs)-configProperty (AxisX acs) = "axisX" .= object (map axisConfigProperty acs)-configProperty (AxisY acs) = "axisY" .= object (map axisConfigProperty acs)-configProperty (AxisLeft acs) = "axisLeft" .= object (map axisConfigProperty acs)-configProperty (AxisRight acs) = "axisRight" .= object (map axisConfigProperty acs)-configProperty (AxisTop acs) = "axisTop" .= object (map axisConfigProperty acs)-configProperty (AxisBottom acs) = "axisBottom" .= object (map axisConfigProperty acs)-configProperty (AxisBand acs) = "axisBand" .= object (map axisConfigProperty acs)-configProperty (Legend lcs) = "legend" .= object (map legendConfigProperty lcs)-configProperty (MarkStyle mps) = mprops_ "mark" mps-configProperty (Projection pps) = "projection" .= object (map projectionProperty pps)-configProperty (AreaStyle mps) = mprops_ "area" mps-configProperty (BarStyle mps) = mprops_ "bar" mps-configProperty (CircleStyle mps) = mprops_ "circle" mps-configProperty (FacetStyle fps) = "facet" .= object (map facetConfigProperty fps)-configProperty (GeoshapeStyle mps) = mprops_ "geoshape" mps-configProperty (HeaderStyle hps) = header_ hps-configProperty (LineStyle mps) = mprops_ "line" mps-configProperty (PointStyle mps) = mprops_ "point" mps-configProperty (RectStyle mps) = mprops_ "rect" mps-configProperty (RuleStyle mps) = mprops_ "rule" mps-configProperty (SquareStyle mps) = mprops_ "square" mps-configProperty (TextStyle mps) = mprops_ "text" mps-configProperty (TickStyle mps) = mprops_ "tick" mps-configProperty (TitleStyle tcs) = "title" .= object (map titleConfigSpec tcs)-configProperty (NamedStyle nme mps) = "style" .= object [mprops_ nme mps]-configProperty (NamedStyles styles) =-  let toStyle = uncurry mprops_-  in "style" .= object (map toStyle styles)-configProperty (Scale scs) = scaleConfig_ scs-configProperty (Stack so) = stackOffset so-configProperty (Range rcs) = "range" .= object (map rangeConfigProperty rcs)-configProperty (SelectionStyle selConfig) =-  let selProp (sel, sps) = selectionLabel sel .= object (map selectionProperty sps)-  in "selection" .= object (map selProp selConfig)-configProperty (TrailStyle mps) = mprops_ "trail" mps-configProperty (View vcs) = "view" .= object (map viewConfigProperty vcs)---{-|--Axis configuration options for customising all axes. See the-<https://vega.github.io/vega-lite/docs/axis.html#general-config Vega-Lite documentation>-for more details.--The @TitleMaxLength@ constructor was removed in release @0.4.0.0@. The-@TitleLimit@ constructor should be used instead.---}-data AxisConfig-    = BandPosition Double-      -- ^ The default axis band position.-    | Domain Bool-      -- ^ Should the axis domain be displayed?-    | DomainColor Color-      -- ^ The axis domain color.-    | DomainDash [Double]-      -- ^ The dash style of the domain (alternating stroke, space lengths-      --   in pixels).-      ---      --   @since 0.4.0.0-    | DomainDashOffset Double-      -- ^ The pixel offset at which to start drawing the domain dash array.-      ---      --   @since 0.4.0.0-    | DomainOpacity Opacity-      -- ^ The axis domain opacity.-      ---      --   @since 0.4.0.0-    | DomainWidth Double-      -- ^ The width of the axis domain.-    | Grid Bool-      -- ^ Should an axis grid be displayed?-    | GridColor Color-      -- ^ The color for the grid.-    | GridDash [Double]-      -- ^ The dash style of the grid (alternating stroke, space lengths-      --   in pixels).-    | GridDashOffset Double-      -- ^ The pixel offset at which to start drawing the grid dash array.-      ---      --   @since 0.4.0.0-    | GridOpacity Opacity-      -- ^ The opacity of the grid.-    | GridWidth Double-      -- ^ The width of the grid lines.-    | Labels Bool-      -- ^ Should labels be added to an axis?-    | LabelAlign HAlign-      -- ^ The horizontal alignment for labels.-      ---      --   @since 0.4.0.0-    | LabelAngle Angle-      -- ^ The angle at which to draw labels.-    | LabelBaseline VAlign-      -- ^ The vertical alignment for labels.-      ---      --   @since 0.4.0.0-    | LabelNoBound-      -- ^ No boundary overlap check is applied to labels. This is the-      --   default behavior.-      ---      --   See also 'LabelBound' and 'LabelBoundValue'.-      ---      --   @since 0.4.0.0-    | LabelBound-      -- ^ Labels are hidden if they exceed the axis range by more than 1-      --   pixel.-      ---      --   See also 'LabelNoBound' and 'LabelBoundValue'.-      ---      --   @since 0.4.0.0-    | LabelBoundValue Double-      -- ^ Labels are hidden if they exceed the axis range by more than-      --   the given number of pixels.-      ---      --   See also 'LabelNoBound' and 'LabelBound'.-      ---      --   @since 0.4.0.0-    | LabelColor Color-      -- ^ The label color.-    | LabelNoFlush-      -- ^ The labels are not aligned flush to the scale. This is the-      --   default for non-continuous X scales.-      ---      --   See also 'LabelFlush' and 'LabelFlushValue'.-      ---      --   @since 0.4.0.0-    | LabelFlush-      -- ^ The first and last axis labels are aligned flush to the scale-      --   range.-      ---      --   See also 'LabelNoFlush' and 'LabelFlushValue'.-      ---      --   @since 0.4.0.0-    | LabelFlushValue Double-      -- ^ The labels are aligned flush, and the parameter determines-      --   the extra offset, in pixels, to apply to the first and last-      --   labels. This can help the labels better group (visually) with-      --   the corresponding axis ticks.-      ---      --   See also 'LabelNoFlush' and 'LabelFlush'.-      ---      --   @since 0.4.0.0-    | LabelFlushOffset Double-      -- ^ The number of pixels to offset flush-adjusted labels.-      ---      --   @since 0.4.0.0-    | LabelFont T.Text-      -- ^ The font for the label.-    | LabelFontSize Double-      -- ^ The font size of the label.-    | LabelFontStyle T.Text-      -- ^ The font style of the label.-      ---      --   @since 0.4.0.0-    | LabelFontWeight FontWeight-      -- ^ The font weight of the label.-      ---      --   @since 0.4.0.0-    | LabelLimit Double-      -- ^ The maximum width of a label, in pixels.-    | LabelOpacity Opacity-      -- ^ The opacity of the label.-      ---      --   @since 0.4.0.0-    | LabelOverlap OverlapStrategy-      -- ^ How should overlapping labels be displayed?-    | LabelPadding Double-      -- ^ The padding, in pixels, between the label and the axis.-    | LabelSeparation Double-      -- ^ The minimum separation, in pixels, between label bounding boxes-      --   for them to be considered non-overlapping. This is ignored if-      --   the 'LabelOverlap' strategy is 'ONone'.-      ---      --   @since 0.4.0.0-    | MaxExtent Double-      -- ^ The maximum extent, in pixels, that axis ticks and labels should use.-      --   This determines a maxmium offset value for axis titles.-    | MinExtent Double-      -- ^ The minimum extent, in pixels, that axis ticks and labels should use.-      --   This determines a minmium offset value for axis titles.-    | NoTitle-      -- ^ Do not draw a title for this axis.-      ---      --   @since 0.4.0.0-    | Orient Side-      -- ^ The orientation of the axis.-      ---      --   @since 0.4.0.0-    | ShortTimeLabels Bool-      -- ^ Should an axis use short time labels (abbreviated month and week-day names)?-    | Ticks Bool-      -- ^ Should tick marks be drawn on an axis?-    | TickColor Color-      -- ^ The color of the ticks.-    | TickDash [Double]-      -- ^ The dash style of the ticks (alternating stroke, space lengths-      --   in pixels).-    | TickDashOffset Double-      -- ^ The pixel offset at which to start drawing the tick dash array.-      ---      --   @since 0.4.0.0-    | TickExtra Bool-      -- ^ Should an extra axis tick mark be added for the initial position of-      --   the axis?-      ---      --   @since 0.4.0.0-    | TickOffset Double-      -- ^ The position offset, in pixels, to apply to ticks, labels, and grid lines.-      ---      --   @since 0.4.0.0-    | TickOpacity Opacity-      -- ^ The opacity of the ticks.-      ---      --   @since 0.4.0.0-    | TickRound Bool-      -- ^ Should pixel position values be rounded to the nearest integer?-    | TickSize Double-      -- ^ The size of the tick marks in pixels.-    | TickWidth Double-      -- ^ The width of the tick marks in pixels.-    | TitleAlign HAlign-      -- ^ The horizontal alignment of the axis title.-    | TitleAnchor APosition-      -- ^ The text anchor position for placing axis titles.-      ---      --   @since 0.4.0.0-    | TitleAngle Angle-      -- ^ The angle of the axis title.-    | TitleBaseline VAlign-      -- ^ The vertical alignment of the axis title.-    | TitleColor Color-      -- ^ The color of the axis title.-    | TitleFont T.Text-      -- ^ The font for the axis title.-    | TitleFontSize Double-      -- ^ The font size of the axis title.-    | TitleFontStyle T.Text-      -- ^ The font style of the axis title.-      ---      --   @since 0.4.0.0-    | TitleFontWeight FontWeight-      -- ^ The font weight of the axis title.-    | TitleLimit Double-      -- ^ The maximum allowed width of the axis title, in pixels.-    | TitleOpacity Opacity-      -- ^ The opacity of the axis title.-      ---      --   @since 0.4.0.0-    | TitlePadding Double-      -- ^ The padding, in pixels, between title and axis.-    | TitleX Double-      -- ^ The X coordinate of the axis title, relative to the axis group.-    | TitleY Double-      -- ^ The Y coordinate of the axis title, relative to the axis group.---axisConfigProperty :: AxisConfig -> LabelledSpec-axisConfigProperty (BandPosition x) = "bandPosition" .= x-axisConfigProperty (Domain b) = "domain" .= b-axisConfigProperty (DomainColor c) = "domainColor" .= c-axisConfigProperty (DomainDash ds) = "domainDash" .= ds-axisConfigProperty (DomainDashOffset x) = "domainDashOffset" .= x-axisConfigProperty (DomainOpacity x) = "domainOpacity" .= x-axisConfigProperty (DomainWidth w) = "domainWidth" .= w-axisConfigProperty (Grid b) = "grid" .= b-axisConfigProperty (GridColor c) = "gridColor" .= c-axisConfigProperty (GridDash ds) = "gridDash" .= ds-axisConfigProperty (GridDashOffset x) = "gridDashOffset" .= x-axisConfigProperty (GridOpacity o) = "gridOpacity" .= o-axisConfigProperty (GridWidth x) = "gridWidth" .= x-axisConfigProperty (Labels b) = "labels" .= b-axisConfigProperty (LabelAlign ha) = "labelAlign" .= hAlignLabel ha-axisConfigProperty (LabelAngle angle) = "labelAngle" .= angle-axisConfigProperty (LabelBaseline va) = "labelBaseline" .= vAlignLabel va-axisConfigProperty LabelNoBound = "labelBound" .= False-axisConfigProperty LabelBound = "labelBound" .= True-axisConfigProperty (LabelBoundValue x) = "labelBound" .= x-axisConfigProperty LabelNoFlush = "labelFlush" .= False-axisConfigProperty LabelFlush = "labelFlush" .= True-axisConfigProperty (LabelFlushValue x) = "labelFlush" .= x-axisConfigProperty (LabelFlushOffset x) = "labelFlushOffset" .= x-axisConfigProperty (LabelColor c) = "labelColor" .= c-axisConfigProperty (LabelFont f) = "labelFont" .= f-axisConfigProperty (LabelFontSize x) = "labelFontSize" .= x-axisConfigProperty (LabelFontStyle s) = "labelFontStyle" .= s-axisConfigProperty (LabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw-axisConfigProperty (LabelLimit x) = "labelLimit" .= x-axisConfigProperty (LabelOpacity x) = "labelOpacity" .= x-axisConfigProperty (LabelOverlap strat) = "labelOverlap" .= overlapStrategyLabel strat-axisConfigProperty (LabelPadding pad) = "labelPadding" .= pad-axisConfigProperty (LabelSeparation x) = "labelSeparation" .= x-axisConfigProperty (MaxExtent n) = "maxExtent" .= n-axisConfigProperty (MinExtent n) = "minExtent" .= n-axisConfigProperty NoTitle = "title" .= A.Null-axisConfigProperty (Orient orient) = "orient" .= sideLabel orient-axisConfigProperty (ShortTimeLabels b) = "shortTimeLabels" .= b-axisConfigProperty (Ticks b) = "ticks" .= b-axisConfigProperty (TickColor c) = "tickColor" .= c-axisConfigProperty (TickDash ds) = "tickDash" .= ds-axisConfigProperty (TickDashOffset x) = "tickDashOffset" .= x-axisConfigProperty (TickExtra b) = "tickExtra" .= b-axisConfigProperty (TickOffset x) = "tickOffset" .= x-axisConfigProperty (TickOpacity x) = "tickOpacity" .= x-axisConfigProperty (TickRound b) = "tickRound" .= b-axisConfigProperty (TickSize x) = "tickSize" .= x-axisConfigProperty (TickWidth x) = "tickWidth" .= x-axisConfigProperty (TitleAlign algn) = "titleAlign" .= hAlignLabel algn-axisConfigProperty (TitleAnchor a) = "titleAnchor" .= anchorLabel a-axisConfigProperty (TitleAngle x) = "titleAngle" .= x-axisConfigProperty (TitleBaseline va) = "titleBaseline" .= vAlignLabel va-axisConfigProperty (TitleColor c) = "titleColor" .= c-axisConfigProperty (TitleFont f) = "titleFont" .= f-axisConfigProperty (TitleFontSize x) = "titleFontSize" .= x-axisConfigProperty (TitleFontStyle s) = "titleFontStyle" .= s-axisConfigProperty (TitleFontWeight w) = "titleFontWeight" .= fontWeightSpec w-axisConfigProperty (TitleLimit x) = "titleLimit" .= x-axisConfigProperty (TitleOpacity x) = "titleOpacity" .= x-axisConfigProperty (TitlePadding x) = "titlePadding" .= x-axisConfigProperty (TitleX x) = "titleX" .= x-axisConfigProperty (TitleY y) = "titleY" .= y---{-|--Used for creating logical compositions. For example--@-'color'-    [ 'MSelectionCondition' (Or ('SelectionName' "alex") (SelectionName "morgan"))-        ['MAggregate' 'Count', 'MName' "*", 'MmType' 'Quantitative']-        ['MString' "gray"]-    ]-@--Logical compositions can be nested to any level as shown in this example--@-'Not' ('And' ('Expr' "datum.IMDB_Rating === null") ('Expr' "datum.Rotten_Tomatoes_Rating === null") )-@--}-data BooleanOp-    = Expr T.Text-      -- ^ Expression that should evaluate to either true or false.-      --   Can use any valid-      --   [Vega expression](https://vega.github.io/vega/docs/expressions/).-    | FilterOp Filter-      -- ^ Convert a 'Filter' into a 'BooleanOp' so that it may be used as-      --   part of a more complex expression.-      ---      --   For example (using 'Data.Function.&' to apply 'FilterOp' to a filter):-      ---      --   @-      --   trans = 'transform'-      --             . 'filter' ('FCompose'-      --                        ('And'-      --                          ('FValid' "IMDB_Rating" & 'FilterOp')-      --                          ('FValid' "Rotten_Tomatoes_Rating" & 'FilterOp')-      --                        )-      --                      )-      --   @-      ---      --   @since 0.4.0.0-    | FilterOpTrans MarkChannel Filter-      -- ^ Combine a data-transformation operation with a filter before-      --   converting into a boolean operation. This can be useful when-      --   working with dates, such as the following exampe, which aggregates-      --   a set of dates into years, and filters only those years between-      --   2010 and 2017 (inclusive). The final expression is converted-      --   back into a 'BooleanOp' with 'FCompose' (combined using-      --   'Data.Function.&').-      ---      --   @-      --   'filter' ('FRange' "date" ('DateRange' ['DTYear' 2010] ['DTYear' 2017])-      --           & 'FilterOpTrans' ('MTimeUnit' 'Year')-      --           & 'FCompose'-      --           )-      --   @-      ---      --   @since 0.4.0.0-    | Selection T.Text  -- TODO: rename Selected since collides with Selection type-      -- ^ Interactive selection that will be true or false as part of-      --   a logical composition.  For example: to filter a dataset so-      --   that only items selected interactively and that have a-      --   weight of more than 30:-      ---      -- @-      -- 'transform'-      --    . 'filter' ('FCompose' ('And' ('Selection' "brush") ('Expr' "datum.weight > 30")))-      -- @-    | SelectionName T.Text-    -- ^  Name a selection that is used as part of a conditional encoding.-    ---    -- @-    -- 'color'-    --    [ 'MSelectionCondition' ('SelectionName' \"myBrush\")-    --        ['MName' \"myField\", 'MmType' 'Nominal']-    --        ['MString' \"grey\"]-    --    ]-    -- @-    | And BooleanOp BooleanOp-      -- ^ Apply an \'and\' Boolean operation as part of a logical composition.-      ---      -- @-      -- 'And' ('Expr' "datum.IMDB_Rating === null") ('Expr' "datum.Rotten_Tomatoes_Rating === null")-      -- @-    | Or BooleanOp BooleanOp-      -- ^ Apply an \'or\' Boolean operation as part of a logical composition.-    | Not BooleanOp-      -- ^ Negate the given expression.-      ---      -- @-      -- 'Not' ('And' ('Expr' "datum.IMDB_Rating === null") ('Expr' "datum.Rotten_Tomatoes_Rating === null"))-      -- @--booleanOpSpec :: BooleanOp -> VLSpec-booleanOpSpec (Expr expr) = toJSON expr-booleanOpSpec (FilterOp f) = filterSpec f-booleanOpSpec (FilterOpTrans tr f) = trFilterSpec tr f-booleanOpSpec (SelectionName selName) = toJSON selName-booleanOpSpec (Selection sel) = object ["selection" .= sel]-booleanOpSpec (And operand1 operand2) = object ["and" .= [booleanOpSpec operand1, booleanOpSpec operand2]]-booleanOpSpec (Or operand1 operand2) = object ["or" .= [booleanOpSpec operand1, booleanOpSpec operand2]]-booleanOpSpec (Not operand) = object ["not" .= booleanOpSpec operand]---{-|--Type of filtering operation. See the-<https://vega.github.io/vega-lite/docs/filter.html Vega-Lite documentation>-for details.--These can also be included into a 'BooleanOp' expression using 'FilterOp'-and 'FilterOpTrans'-(as of version @0.4.0.0@).---}-data Filter-    = FEqual T.Text DataValue-      -- ^ Filter a data stream so that only data in a given field equal to-      --   the given value are used.-    | FLessThan T.Text DataValue-      -- ^ Filter a data stream so that only data in a given field less than the given-      --   value are used.-      ---      --   @since 0.4.0.0-    | FLessThanEq T.Text DataValue-      -- ^ Filter a data stream so that only data in a given field less than,-      --   or equal to, the given value are used.-      ---      --   @since 0.4.0.0-    | FGreaterThan T.Text DataValue-      -- ^ Filter a data stream so that only data in a given field greater than the given-      --   value are used.-      ---      --   @since 0.4.0.0-    | FGreaterThanEq T.Text DataValue-      -- ^ Filter a data stream so that only data in a given field greater than,-      --   or equal to, the given value are used.-      ---      --   @since 0.4.0.0-    | FExpr T.Text-      -- ^ Filter a data stream so that only data that satisfy the given predicate-      --   expression are used.-    | FCompose BooleanOp-      -- ^ Build up a filtering predicate through logical composition such-      --   as 'And' and 'Or'.-      ---      --   The following fgragment will apply a filter to identify only-      --   those items selected interactively and that represent ages-      --   over 65:-      ---      --   @-      --   trans = 'transform'-      --             . 'filter'-      --                 ('FCompose'-      --                   ('And' ('Selection' "brush") ('Expr' "datum.age > 65"))-      --                 )-      --   @-    | FSelection T.Text-      -- ^ Filter a data stream so that only data in a given field that are-      --   within the given interactive selection are used.-      ---      --   @-      --   sel = 'selection' . 'select' \"myBrush\" 'Interval' ['Encodings' ['ChX']]-      --   trans = 'transform' . 'filter' ('FSelection' \"myBrush\")-      --   @-    | FOneOf T.Text DataValues-      -- ^ Filter a data stream so that only data in a given field contained in the given-      --   list of values are used.-    | FRange T.Text FilterRange-      -- ^ Filter a data stream so that only data in a given field-      --   that are within the given range are used.-      ---      --   For example:-      ---      --   @-      --   'filter' ('FRange' "date" ('DateRange' ['DTYear' 2006] ['DTYear' 2016])-      --   @-      ---      --   See 'FilterOpTrans' for more use cases.-    | FValid T.Text-      -- ^ Filter a data stream so that only valid data (i.e. not null or NaN) in a given-      --   field are used.-      ---      --   @since 0.4.0.0---fop_ :: T.Text -> T.Text -> DataValue -> [LabelledSpec]-fop_ field label val = [field_ field, label .= dataValueSpec val]--filterProperty :: Filter -> [LabelledSpec]--filterProperty (FEqual field val) = fop_ field "equal" val-filterProperty (FLessThan field val) = fop_ field "lt" val-filterProperty (FLessThanEq field val) = fop_ field "lte" val-filterProperty (FGreaterThan field val) = fop_ field "gt" val-filterProperty (FGreaterThanEq field val) = fop_ field "gte" val--filterProperty (FSelection selName) = ["selection" .= selName]--filterProperty (FRange field vals) =-  let ans = case vals of-              NumberRange mn mx -> map toJSON [mn, mx]-              DateRange dMin dMax -> [process dMin, process dMax]--      process [] = A.Null-      process dts = object (map dateTimeProperty dts)--  in [field_ field, "range" .= ans]--filterProperty (FOneOf field vals) =-  let ans = case vals of-              Numbers xs -> map toJSON xs-              DateTimes dts -> map (object . map dateTimeProperty) dts-              Strings ss -> map toJSON ss-              Booleans bs -> map toJSON bs--  in [field_ field, "oneOf" .= ans]--filterProperty (FValid field) = [field_ field, "valid" .= True]-filterProperty _ = []  -- ignore FExpr and FCompose---filterSpec :: Filter -> VLSpec-filterSpec (FExpr expr) = toJSON expr-filterSpec (FCompose boolExpr) = booleanOpSpec boolExpr-filterSpec f = object (filterProperty f)--trFilterSpec :: MarkChannel -> Filter -> VLSpec-trFilterSpec _ (FExpr expr) = toJSON expr-trFilterSpec _ (FCompose boolExpr) = booleanOpSpec boolExpr-trFilterSpec mchan fi = object (markChannelProperty mchan <> filterProperty fi)---{-|--A pair of filter range data values. The first argument is the inclusive minimum-vale to accept and the second the inclusive maximum.--}-data FilterRange-    = NumberRange Double Double-    | DateRange [DateTime] [DateTime]---{-|--Specifies the type and content of geometry specifications for programatically-creating GeoShapes. These can be mapped to the-<https://tools.ietf.org/html/rfc7946#section-3.1 GeoJson geometry object types>-where the pluralised type names refer to their @Multi@ prefixed equivalent in the-GeoJSON specification.--}-data Geometry-    = GeoPoint Double Double-    -- ^ The GeoJson geometry @point@ type.-    | GeoPoints [(Double, Double)]-    -- ^ The GeoJson geometry @multi-point@ type.-    | GeoLine [(Double, Double)]-    -- ^ The GeoJson geometry @line@ type.-    | GeoLines [[(Double, Double)]]-    -- ^ The GeoJson geometry @multi-line@ type.-    | GeoPolygon [[(Double, Double)]]-    -- ^ The GeoJson geometry @polygon@ type.-    | GeoPolygons [[[(Double, Double)]]]-    -- ^ The GeoJson geometry @multi-polygon@ type.---{-|--Specifies a geometric object to be used in a geoShape specification. The first-parameter is the geometric type, the second an optional list of properties to be-associated with the object.--@-'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []-@--}-geometry :: Geometry -> [(T.Text, DataValue)] -> VLSpec-geometry gType properties =-  object ([ ("type", fromT "Feature")-          , ("geometry", geometryTypeSpec gType) ]-          <> if null properties-             then []-             else [("properties",-                    object (map (second dataValueSpec) properties))]-         )---geometryTypeSpec :: Geometry -> VLSpec-geometryTypeSpec gType =-  let toCoords :: [(Double, Double)] -> VLSpec-      toCoords = toJSON -- rely on Aeson converting a pair to a 2-element list--      toCoordList :: [[(Double, Double)]] -> VLSpec-      toCoordList = toJSON . map toCoords  -- this is just toJSON isn't it?--      -- can we replace this infinite tower of toJSON calls with one toJSON call?-      (ptype, cs) = case gType of-        GeoPoint x y -> ("Point", toJSON [x, y])-        GeoPoints coords -> ("MultiPoint", toCoords coords)-        GeoLine coords -> ("LineString", toCoords coords)-        GeoLines coords -> ("MultiLineString", toCoordList coords)-        GeoPolygon coords -> ("Polygon", toCoordList coords)-        GeoPolygons ccoords -> ("MultiPolygon", toJSON (map toCoordList ccoords))--  in object [("type", ptype), ("coordinates", cs)]---{-|--Generate a data source that is a sphere for bounding global geographic data.-The sphere will be subject to whatever projection is specified for the view.--@-'toVegaLite'-    [ 'sphere'-    , 'projection' [ 'PrType' 'Orthographic' ]-    , 'mark' 'Geoshape' [ 'MFill' "aliceblue" ]-    ]-@--@since 0.4.0.0--}-sphere :: Data-sphere = (VLData, object ["sphere" .= True])---{-|--Generate a grid of lines of longitude (meridians) and latitude-(parallels).--@-let proj = 'projection' [ 'PrType' 'Orthographic' ]-    sphereSpec = 'asSpec' [ 'sphere'-                        , 'mark' 'Geoshape' [ 'MFill' "aliceblue" ] ]-    gratSpec =-        'asSpec'-            [ 'graticule' [ 'GrStep' (5, 5) ]-            , 'mark' 'Geoshape' [ 'MFilled' False, 'MStrokeWidth' 0.3 ]-            ]-in 'toVegaLite' [ proj, 'layer' [ sphereSpec, gratSpec ] ]-@--@since 0.4.0.0---}-graticule ::-  [GraticuleProperty] -- ^ An empty list uses the default parameters-  -> Data-graticule [] = (VLData, object ["graticule" .= True])-graticule grProps =-  (VLData, object ["graticule" .= object (map graticuleProperty grProps)])---{-|--Determine the properties of graticules. See the-<https://vega.github.io/vega-lite/docs/data.html#graticule Vega-Lite documentation> for details.--@since 0.4.0.0---}-data GraticuleProperty-    = GrExtent (Double, Double) (Double, Double)-    -- ^ Define the extent of both the major and minor graticules.-    --   The range is given as longitude, latitude pairs of the-    --   minimum and then maximum extent. The units are degrees.-    | GrExtentMajor (Double, Double) (Double, Double)-    -- ^ As @GrExtent@ but for the major graticule lines only.-    | GrExtentMinor (Double, Double) (Double, Double)-    -- ^ As @GrExtent@ but for the minor graticule lines only.-    | GrStep (Double, Double)-    -- ^ The step angles for the graticule lines, given as a longitude,-    --   latitude pair defining the EW and NS intervals respectively.-    --   The units are degrees.-    ---    --   By default major graticule lines extend to both poles but the-    --   minor lines stop at ±80 degrees latitude.-    | GrStepMajor (Double, Double)-    -- ^ As @GrStep@ but for the major graticule lines only.-    ---    --   The default is @(90, 360)@.-    | GrStepMinor (Double, Double)-    -- ^ As @GrStep@ but for the minor graticule lines only.-    ---    --   The default is @(10, 10)@.-    | GrPrecision Double-    -- ^ The precision of the graticule. The units are degrees.-    --   A smaller value reduces visual artifacts (steps) but takes longer-    --   to render.-    ---    --   The default is @2.5@.---graticuleProperty :: GraticuleProperty -> LabelledSpec-graticuleProperty (GrExtent (lng1, lat1) (lng2, lat2)) =-  "extent" .= [[lng1, lat1], [lng2, lat2]]-graticuleProperty (GrExtentMajor (lng1, lat1) (lng2, lat2)) =-  "extentMajor" .= [[lng1, lat1], [lng2, lat2]]-graticuleProperty (GrExtentMinor (lng1, lat1) (lng2, lat2)) =-  "extentMinor" .= [[lng1, lat1], [lng2, lat2]]-graticuleProperty (GrStep (lng, lat)) = "step" .= [lng, lat]-graticuleProperty (GrStepMajor (lng, lat)) = "stepMajor" .= [lng, lat]-graticuleProperty (GrStepMinor (lng, lat)) = "stepMinor" .= [lng, lat]-graticuleProperty (GrPrecision x) = "precision" .= x---{-|--Indicates whether or not a scale domain should be independent of others in a-composite visualization. See the-<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation> for-details.--For use with 'Resolve'.---}-data Resolution-    = Shared-    | Independent---resolutionLabel :: Resolution -> T.Text-resolutionLabel Shared = "shared"-resolutionLabel Independent = "independent"---{-|--Used to determine how a channel's axis, scale or legend domains should be resolved-if defined in more than one view in a composite visualization. See the-<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation>-for details.--}-data Resolve-    = RAxis [(Channel, Resolution)]-    | RLegend [(Channel, Resolution)]-    | RScale [(Channel, Resolution)]---resolveProperty :: Resolve -> LabelledSpec-resolveProperty res =-  let (nme, rls) = case res of-        RAxis chRules -> ("axis", chRules)-        RLegend chRules -> ("legend", chRules)-        RScale chRules -> ("scale", chRules)--      ans = map (\(ch, rule) -> channelLabel ch .= resolutionLabel rule) rls-  in (nme, object ans)---{-|--Represents a facet header property. For details, see the-<https://vega.github.io/vega-lite/docs/facet.html#header Vega-Lite documentation>.--Labels refer to the title of each sub-plot in a faceted view and-title is the overall title of the collection.---}---- TODO: should there be a HLabelBaseline, HTitleFontStyle, ...?---       However, the following covers the vega-lite 3.3.0 schema--data HeaderProperty-    = HFormat T.Text-      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html) for-      --   facet header (title) values. To distinguish between formatting as numeric values-      --   and data/time values, additionally use 'HFormatAsNum' or 'HFormatAsTemporal'.-    | HFormatAsNum-      -- ^ Facet headers should be formatted as numbers. Use a-      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)-      --   with 'HFormat'.-      ---      -- @since 0.4.0.0-    | HFormatAsTemporal-      -- ^ Facet headers should be formatted as dates or times. Use a-      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)-      --   with 'HFormat'.-      ---      -- @since 0.4.0.0-    | HTitle T.Text-      -- ^ The title for the facets.-    | HNoTitle-      -- ^ Draw no title for the facets.-      ---      -- @since 0.4.0.0-    | HLabelAlign HAlign-      -- ^ The horizontal alignment of the labels.-      ---      -- @since 0.4.0.0-    | HLabelAnchor APosition-      -- ^ The anchor position for the labels.-      ---      -- @since 0.4.0.0-    | HLabelAngle Angle-      -- ^ The angle to draw the labels.-      ---      -- @since 0.4.0.0-    | HLabelColor Color-      -- ^ The color of the labels.-      ---      -- @since 0.4.0.0-    | HLabelFont T.Text-      -- ^ The font for the labels.-      ---      -- @since 0.4.0.0-    | HLabelFontSize Double-      -- ^ The font size for the labels.-      ---      -- @since 0.4.0.0-    | HLabelLimit Double-      -- ^ The maximum length of each label.-      ---      -- @since 0.4.0.0-    | HLabelOrient Side-      -- ^ The position of the label relative to its sub-plot.-      ---      -- @since 0.4.0.0-    | HLabelPadding Double-      -- ^ The spacing in pixels between the label and its sub-plot.-      ---      -- @since 0.4.0.0-    | HTitleAlign HAlign-      -- ^ The horizontal alignment of the title.-      ---      -- @since 0.4.0.0-    | HTitleAnchor APosition-      -- ^ The anchor position for the title.-      ---      -- @since 0.4.0.0-    | HTitleAngle Angle-      -- ^ The angle to draw the title.-      ---      -- @since 0.4.0.0-    | HTitleBaseline VAlign-      -- ^ The vertical alignment of the title.-      ---      -- @since 0.4.0.0-    | HTitleColor Color-      -- ^ The color of the title.-      ---      -- @since 0.4.0.0-    | HTitleFont T.Text-      -- ^ The font for the title.-      ---      -- @since 0.4.0.0-    | HTitleFontSize Double-      -- ^ The font size for the title.-      ---      -- @since 0.4.0.0-    | HTitleFontWeight T.Text-      -- ^ The font weight for the title.-      ---      -- @since 0.4.0.0-    | HTitleLimit Double-      -- ^ The maximum length of the title.-      ---      -- @since 0.4.0.0-    | HTitleOrient Side-      -- ^ The position of the title relative to the sub-plots.-      ---      -- @since 0.4.0.0-    | HTitlePadding Double-      -- ^ The spacing in pixels between the title and the labels.-      ---      -- @since 0.4.0.0---headerProperty :: HeaderProperty -> LabelledSpec-headerProperty (HFormat fmt) = "format" .= fmt-headerProperty HFormatAsNum = "formatType" .= fromT "number"-headerProperty HFormatAsTemporal = "formatType" .= fromT "time"-headerProperty (HTitle ttl) = "title" .= ttl-headerProperty HNoTitle = "title" .= A.Null-headerProperty (HLabelAlign ha) = "labelAlign" .= hAlignLabel ha-headerProperty (HLabelAnchor a) = "labelAnchor" .= anchorLabel a-headerProperty (HLabelAngle x) = "labelAngle" .= x-headerProperty (HLabelColor s) = "labelColor" .= s-headerProperty (HLabelFont s) = "labelFont" .= s-headerProperty (HLabelFontSize x) = "labelFontSize" .= x-headerProperty (HLabelLimit x) = "labelLimit" .= x-headerProperty (HLabelOrient orient) = "labelOrient" .= sideLabel orient-headerProperty (HLabelPadding x) = "labelPadding" .= x-headerProperty (HTitleAlign ha) = "titleAlign" .= hAlignLabel ha-headerProperty (HTitleAnchor a) = "titleAnchor" .= anchorLabel a-headerProperty (HTitleAngle x) = "titleAngle" .= x-headerProperty (HTitleBaseline va) = "titleBaseline" .= vAlignLabel va-headerProperty (HTitleColor s) = "titleColor" .= s-headerProperty (HTitleFont s) = "titleFont" .= s-headerProperty (HTitleFontWeight s) = "titleFontWeight" .= s-headerProperty (HTitleFontSize x) = "titleFontSize" .= x-headerProperty (HTitleLimit x) = "titleLimit" .= x-headerProperty (HTitleOrient orient) = "titleOrient" .= sideLabel orient-headerProperty (HTitlePadding x) = "titlePadding" .= x----- | Types of hyperlink channel property used for linking marks or text to URLs.--data HyperlinkChannel-    = HName T.Text-      -- ^ Field used for encoding with a hyperlink channel.-    | HRepeat Arrangement-      -- ^ Reference in a hyperlink channel to a field name generated by 'repeatFlow'-      --  or 'repeat'. The parameter identifies whether reference is being made to-      -- fields that are to be arranged in columns, in rows, or a with a flow layout.-    | HmType Measurement-      -- ^ Level of measurement when encoding with a hyperlink channel.-    | HBin [BinProperty]-      -- ^ Discretize numeric values into bins when encoding with a hyperlink channel.-    | HBinned-      -- ^ Indicate that data encoded with a hyperlink channel are already binned.-      ---      --   @since 0.4.0.0-    | HAggregate Operation-      -- ^ Compute aggregate summary statistics for a field to be encoded with a-      -- hyperlink channel.-    | HTimeUnit TimeUnit-    | HSelectionCondition BooleanOp [HyperlinkChannel] [HyperlinkChannel]-      -- ^ Make a hyperlink channel conditional on interactive selection. The first parameter-      --   provides the selection to evaluate, the second the encoding to apply if the hyperlink-      --   has been selected, the third the encoding if it is not selected.-    | HDataCondition [(BooleanOp, [HyperlinkChannel])] [HyperlinkChannel]-      -- ^ Make a hyperlink channel conditional on one or more predicate expressions. The first-      --   parameter is a list of tuples each pairing an expression to evaluate with the encoding-      --   if that expression is @True@. The second is the encoding if none of the expressions-      --   evaluate as @True@.-      ---      --   The arguments to this constructor have changed in @0.4.0.0@-      --   to support multiple expressions.-    | HString T.Text-      -- ^ Literal string value when encoding with a hyperlink channel.--hyperlinkChannelProperty :: HyperlinkChannel -> [LabelledSpec]-hyperlinkChannelProperty (HName s) = [field_ s]-hyperlinkChannelProperty (HRepeat arr) = ["field" .= object [repeat_ arr]]-hyperlinkChannelProperty (HmType t) = [mtype_ t]-hyperlinkChannelProperty (HBin bps) = [bin bps]-hyperlinkChannelProperty HBinned = [binned_]-hyperlinkChannelProperty (HSelectionCondition selName ifClause elseClause) =-  selCond_ hyperlinkChannelProperty selName ifClause elseClause-hyperlinkChannelProperty (HDataCondition tests elseClause) =-  dataCond_ hyperlinkChannelProperty tests elseClause-hyperlinkChannelProperty (HTimeUnit tu) = [timeUnit_ tu]-hyperlinkChannelProperty (HAggregate op) = [aggregate_ op]-hyperlinkChannelProperty (HString s) = [value_ s]---------{-|--Create a pair of continuous domain to color mappings suitable for customising-ordered scales. The first parameter is a tuple representing the mapping of the lowest-numeric value in the domain to its equivalent color; the second tuple the mapping-of the highest numeric value to color. If the domain contains any values between-these lower and upper bounds they are interpolated according to the scale's interpolation-function. This is a convenience function equivalent to specifying separate 'SDomain'-and 'SRange' lists and is safer as it guarantees a one-to-one correspondence between-domain and range values.--@-'color'-    [ 'MName' "year"-    , 'MmType' 'Ordinal'-    , 'MScale' (domainRangeMap (1955, \"rgb(230,149,156)\") (2000, \"rgb(145,26,36)\"))-    ]-@--}--domainRangeMap :: (Double, T.Text) -> (Double, T.Text) -> [ScaleProperty]-domainRangeMap lowerMap upperMap =-  let (domain, range) = unzip [lowerMap, upperMap]-  in [SDomain (DNumbers domain), SRange (RStrings range)]---{-|--Create a set of discrete domain to color mappings suitable for customising categorical-scales. The first item in each tuple should be a domain value and the second the-color value with which it should be associated. It is a convenience function equivalent-to specifying separate 'SDomain' and 'SRange' lists and is safer as it guarantees-a one-to-one correspondence between domain and range values.--@-'color'-    [ 'MName' "weather"-    , 'MmType' Nominal-    , 'MScale' (-        categoricalDomainMap-            [ ( "sun", "yellow" )-            , ( "rain", "blue" )-            , ( "fog", "grey" )-            ]-        )-    ]-@--}--categoricalDomainMap :: [(T.Text, T.Text)] -> [ScaleProperty]-categoricalDomainMap scaleDomainPairs =-  let (domain, range) = unzip scaleDomainPairs-  in [SDomain (DStrings domain), SRange (RStrings range)]---{-|--Create a list of fields to use in set of repeated small multiples. The list of-fields named here can be referenced in an encoding with @'PRepeat' 'Column'@-or @'PRepeat' 'Row'@.---}-data RepeatFields-    = RowFields [T.Text]-    | ColumnFields [T.Text]---repeatFieldsProperty :: RepeatFields -> LabelledSpec-repeatFieldsProperty rfs =-  let (nme, vs) = case rfs of-        RowFields fields -> ("row", fields)-        ColumnFields fields -> ("column", fields)--  in nme .= map toJSON vs---{-|--Types of facet channel property used for creating a composed facet view of small-multiples.---}---- based on schema 3.3.0 #/definitions/FacetFieldDef--data FacetChannel-    = FName T.Text-      -- ^ The name of the field from which to pull a data value.-    | FmType Measurement-      -- ^ The encoded field's type of measurement.-    | FAggregate Operation-      -- ^ Aggregation function for the field.-    | FBin [BinProperty]-      -- ^ Describe how to bin quantitative fields, or whether the-      --   channels are already binned.-    | FHeader [HeaderProperty]-      -- ^ The properties of a facet's header.-    | FSort [SortProperty]-      -- ^ Sort order for the encoded field.-      ---      --   @since 0.4.0.0-    | FTimeUnit TimeUnit-      -- ^ The time-unit for a temporal field.-    | FTitle T.Text-      -- ^ The title for the field.-      ---      --   @since 0.4.0.0-    | FNoTitle-      -- ^ Draw no title.-      ---      -- @since 0.4.0.0--facetChannelProperty :: FacetChannel -> LabelledSpec-facetChannelProperty (FName s) = field_ s-facetChannelProperty (FmType measure) = mtype_ measure-facetChannelProperty (FAggregate op) = aggregate_ op-facetChannelProperty (FBin bps) = bin bps-facetChannelProperty (FHeader hps) = header_ hps-facetChannelProperty (FSort sps) = sort_ sps-facetChannelProperty (FTitle s) = "title" .= s-facetChannelProperty FNoTitle = "title" .= A.Null-facetChannelProperty (FTimeUnit tu) = timeUnit_ tu---{-|--Configuration options for faceted views, used with 'FacetStyle'.--See the-<https://vega.github.io/vega-lite/docs/facet.html#facet-configuration Vega-Lite facet config documentation>.--@since 0.4.0.0---}-data FacetConfig-    = FColumns Int-    -- ^ The maximum number of columns to use in a faceted-flow layout.-    | FSpacing Double-    -- ^ The spacing in pixels between sub-views in a faceted composition.---facetConfigProperty :: FacetConfig -> LabelledSpec-facetConfigProperty (FColumns n) = "columns" .= n-facetConfigProperty (FSpacing x) = "spacing" .= x----- | Types of text channel property used for displaying text as part of the visualization.---- Basing the following partly on vega-lite-3.3.0.json / TextFieldDef--- but that doesn't seem to be sufficient.--data TextChannel-    = TName T.Text-      -- ^ Name of the field used for encoding with a text channel.-    | TAggregate Operation-      -- ^ Compute some aggregate summary statistics for a field to be encoded with a-      --   text channel. The type of aggregation is determined by the given operation-      --   parameter.-    | TBin [BinProperty]-      -- ^ Discretize numeric values into bins when encoding with a text channel.-    | TBinned-      -- ^ Indicate that data encoded with a text channel are already binned.-      ---      --   @since 0.4.0.0-    | TDataCondition [(BooleanOp, [TextChannel])] [TextChannel]-      -- ^ Make a text channel conditional on one or more predicate expressions. The first-      --   parameter is a list of tuples each pairing an expression to evaluate with the encoding-      --   if that expression is @True@. The second is the encoding if none of the expressions-      --   evaluate as @True@.-      ---      --   The arguments to this constructor have changed in @0.4.0.0@-      --   to support multiple expressions.-    | TFormat T.Text-      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html)-      --   for text marks. To distinguish between formatting as numeric values and data/time-      --   values, additionally use 'TFormatAsNum' or 'TFormatAsTemporal'.-    | TFormatAsNum-      -- ^ The text marks should be formatted as numbers. Use a-      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)-      --   with 'TFormat'.-      ---      -- @since 0.4.0.0-    | TFormatAsTemporal-      -- ^ The text marks should be formatted as dates or times. Use a-      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)-      --   with 'TFormat'.-      ---      -- @since 0.4.0.0-    | TmType Measurement-      -- ^ Level of measurement when encoding with a text channel.-    | TRepeat Arrangement-      -- ^ Reference in a text channel to a field name generated by 'repeatFlow'-      --   or 'repeat'. The parameter identifies whether reference is being made to-      --   fields that are to be arranged in columns, in rows, or a with a flow layout.-    | TSelectionCondition BooleanOp [TextChannel] [TextChannel]-      -- ^ Make a text channel conditional on interactive selection. The first parameter-      --   is a selection condition to evaluate; the second the encoding to apply if that-      --   selection is true; the third parameter is the encoding if the selection is false.-    | TTitle T.Text-      -- ^ Title of a field when encoding with a text or tooltip channel.-      ---      --   @since 0.4.0.0-    | TNoTitle-      -- ^ Display no title.-      ---      --   @since 0.4.0.0-    | TTimeUnit TimeUnit-      -- ^ Time unit aggregation of field values when encoding with a text channel.---textChannelProperty :: TextChannel -> [LabelledSpec]-textChannelProperty (TName s) = [field_  s]-textChannelProperty (TAggregate op) = [aggregate_ op]-textChannelProperty (TBin bps) = [bin bps]-textChannelProperty TBinned = [binned_]-textChannelProperty (TFormat fmt) = ["format" .= fmt]-textChannelProperty TFormatAsNum = ["formatType" .= fromT "number"]-textChannelProperty TFormatAsTemporal = ["formatType" .= fromT "time"]-textChannelProperty (TmType measure) = [mtype_ measure]-textChannelProperty (TRepeat arr) = ["field" .= object [repeat_ arr]]-textChannelProperty (TTitle s) = ["title" .= s]-textChannelProperty TNoTitle = ["title" .= A.Null]-textChannelProperty (TTimeUnit tu) = [timeUnit_ tu]-textChannelProperty (TDataCondition tests elseClause) =-  dataCond_ textChannelProperty tests elseClause-textChannelProperty (TSelectionCondition selName ifClause elseClause) =-  selCond_ textChannelProperty selName ifClause elseClause----- | Properties of an ordering channel used for sorting data fields.--data OrderChannel-    = OName T.Text-    | ORepeat Arrangement-      -- ^ Reference in an order channel to a field name generated by 'repeatFlow'-      -- or 'repeat'. The parameter identifies whether reference is being made to-      -- fields that are to be arranged in columns, in rows, or a with a flow layout.-    | OmType Measurement-    | OBin [BinProperty]-    | OAggregate Operation-    | OTimeUnit TimeUnit-    | OSort [SortProperty]---orderChannelProperty :: OrderChannel -> LabelledSpec-orderChannelProperty (OName s) = field_ s-orderChannelProperty (ORepeat arr) = "field" .= object [repeat_ arr]-orderChannelProperty (OmType measure) = mtype_ measure-orderChannelProperty (OBin bps) = bin bps-orderChannelProperty (OAggregate op) = aggregate_ op-orderChannelProperty (OTimeUnit tu) = timeUnit_ tu-orderChannelProperty (OSort ops) = sort_ ops----- | Level of detail channel properties used for creating a grouped channel encoding.--data DetailChannel-    = DName T.Text-    | DmType Measurement-    | DBin [BinProperty]-    | DTimeUnit TimeUnit-    | DAggregate Operation---detailChannelProperty :: DetailChannel -> LabelledSpec-detailChannelProperty (DName s) = field_ s-detailChannelProperty (DmType t) = mtype_ t-detailChannelProperty (DBin bps) = bin bps-detailChannelProperty (DTimeUnit tu) = timeUnit_ tu-detailChannelProperty (DAggregate op) = aggregate_ op---{-|--Provides details of the mapping between a row or column and its field-definitions in a set of faceted small multiples. For details see the-<https://vega.github.io/vega-lite/docs/facet.html#mapping Vega-Lite documentation>.--}-data FacetMapping-    = ColumnBy [FacetChannel]-    | RowBy [FacetChannel]---facetMappingProperty :: FacetMapping -> LabelledSpec-facetMappingProperty (RowBy fFields) =-  "row" .= object (map facetChannelProperty fFields)-facetMappingProperty (ColumnBy fFields) =-  "column" .= object (map facetChannelProperty fFields)---{-|--Create a single global configuration from a list of configuration specifications.-Configurations are applied to all relevant items in the specification. See the-<https://vega.github.io/vega-lite/docs/config.html Vega-Lite documentation> for-more details.--The following example would make axis lines (domain) 2 pixels wide,-remove the border rectangle and require interactive selection of items-to use a double-click:--@-config =-    'configure'-        . 'configuration' ('Axis' [ 'DomainWidth' 1 ])-        . 'configuration' ('View' [ 'ViewStroke' (Just "transparent") ])-        . 'configuration' ('SelectionStyle' [ ( 'Single', [ 'On' \"dblclick\" ] ) ])-@--}-configure :: [LabelledSpec] -> PropertySpec-configure configs = (VLConfig, object configs)----- | Alignment to apply to grid rows and columns generated by a composition---   operator. This version sets the same alignment for rows and columns.------   See also 'alignRC'.------   @since 0.4.0.0--align :: CompositionAlignment -> PropertySpec-align algn = (VLAlign, compositionAlignmentSpec algn)----- | Similar to 'align' but with independent alignments for rows and columns.------   See also 'align'.------   @since 0.4.0.0--alignRC ::-  CompositionAlignment     -- ^ Row alignment-  -> CompositionAlignment  -- ^ Column alignment-  -> PropertySpec-alignRC alRow alCol =-  (VLSpacing, object [ "row" .= compositionAlignmentSpec alRow-                     , "col" .= compositionAlignmentSpec alCol-                     ])----- | Spacing between sub-views in a composition operator.------   See also 'spacingRC'.------   @since 0.4.0.0--spacing ::-  Double   -- ^ Spacing in pixels.-  -> PropertySpec-spacing sp = (VLSpacing, toJSON sp)----- | Set the spacing between the rows and columns.------   See also 'spacing'.------   @since 0.4.0.0--spacingRC ::-  Double      -- ^ Spacing between rows (in pixels).-  -> Double   -- ^ Spacing between columns (in pixels).-  -> PropertySpec-spacingRC spRow spCol = (VLSpacing, object ["row" .= spRow, "column" .= spCol])----- | Are sub-views in a composition operator centred relative to their respective---   rows and columns?------   See also 'centerRC'.------   @since 0.4.0.0--center :: Bool -> PropertySpec-center c = (VLCenter, toJSON c)----- | Are sub-views in a composition operator centred relative to their respective---   rows and columns?------   See also 'center'.------   @since 0.4.0.0--centerRC ::-  Bool     -- ^ Are rows to be centered?-  -> Bool  -- ^ Are columns to be centered?-  -> PropertySpec-centerRC cRow cCol = (VLCenter, object ["row" .= cRow, "col" .= cCol])----- | This is used with 'bounds' to define the extent of a sub plot.------   @since 0.4.0.0--data Bounds-  = Full-    -- ^ Bounds calculation should use the entire plot area (including axes, title,-    --   and legend).-  | Flush-    -- ^ Bounds calculation should take only the specified width and height values for-    --   a sub-view. Useful when attempting to place sub-plots without axes or legends into-    --   a uniform grid structure.---boundsSpec :: Bounds -> VLSpec-boundsSpec Full = "full"-boundsSpec Flush = "flush"---{-|--Bounds calculation method to use for determining the extent of a sub-plot in-a composed view.--@since 0.4.0.0--}-bounds :: Bounds -> PropertySpec-bounds bnds = (VLBounds, boundsSpec bnds)---{-|--The list of specifications to be juxtaposed horizontally in a flow-layout of views.--The number of columns in the flow layout can be set with 'columns'-and, if not specified, will default to a single row of unlimited columns.--@-let dvals = 'dataSequenceAs' 0 6.28 0.1 \"x\"-    trans = 'transform'-              . 'calculateAs' \"sin(datum.x)\" \"sinX\"-              . 'calculateAs' \"cos(datum.x)\" \"cosX\"-    enc = 'encoding'-            . 'position' 'X' ['PName' \"x\", 'PmType' 'Quantitative']-    encCos = enc . 'position' 'Y' ['PName' \"cosX\", 'PmType' 'Quantitative']-    encSin = enc . 'position' 'Y' ['PName' \"sinX\", 'PmType' 'Quantitative']--in toVegaLite [ dvals-              , trans []-              , 'vlConcat' [ 'asSpec' [encCos [], 'mark' 'Line' []]-                         , 'asSpec' [encSin [], 'mark' 'Line' []]-                         ]-              ]-@--This is named @concat@ in Elm VegaLite but has been renamed here-to avoid conflicting with the Prelude.--@since 0.4.0.0---}-vlConcat :: [VLSpec] -> PropertySpec-vlConcat specs = (VLConcat, toJSON specs)---{-|--Defines the fields that will be used to facet a view in rows or columns to create-a set of small multiples. This is used where the encoding of the visualization in small-multiples is identical, but data for each is grouped by the given fields. When-creating a faceted view in this way you also need to define a full specification-to apply to each of those facets using 'asSpec'.--See the-<https://vega.github.io/vega-lite/docs/facet.html Vega-Lite documentation>-for further details.--@-'toVegaLite'-    [ facet [ 'RowBy' [ 'FName' \"Month\", 'FmType' 'Ordinal' ]-            , 'ColumnBy' [ 'FName' \"Week\", 'FmType' 'Ordinal' ]-            ]-    , 'specification' spec-    ]-@--See also 'facetFlow'.---}--facet :: [FacetMapping] -> PropertySpec-facet fMaps = (VLFacet, object (map facetMappingProperty fMaps))---{-|--Facet a view to create small multiples in a flow layout. Used when the encoding-of the visualization in small multiples is identical, but data for each is grouped-by the given fields. When creating a faceted view in this way you also need to-define a full specification to apply to each of those facets using 'asSpec'.--Small multiples will be laid out from left to right, moving on to new rows only-if the number of plots exceeds an optional column limit (specified via 'columns').--@-'toVegaLite'-    [ facetFlow [ 'FName' \"Origin\", 'FmType' 'Nominal' ]-    , 'specification' spec-    ]-@--See also 'facet'.--@since 0.4.0.0--}-facetFlow :: [FacetChannel] -> PropertySpec-facetFlow fFields = (VLFacet, object (map facetChannelProperty fFields))---{-|--Overrides the default height of the visualization. If not specified the height-will be calculated based on the content of the visualization. See-'autosize' for customization of the content sizing relative to this-setting.--@-'toVegaLite'-    [ 'height' 300-    , 'dataFromUrl' "data/population.json" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-height :: Double -> PropertySpec-height h = (VLHeight, toJSON h)---{-|--Configuration options for concatenated views, used with 'ConcatStyle'.--@since 0.4.0.0---}-data ConcatConfig-    = ConcatColumns Int-      -- ^ The maximum number of columns to use in a concatenated flow layout.-    | ConcatSpacing Double-      -- ^ The spacing in pixels between sub-views in a concatenated view.---concatConfigProperty :: ConcatConfig -> LabelledSpec-concatConfigProperty (ConcatColumns n) = "columns" .= n-concatConfigProperty (ConcatSpacing x) = "spacing" .= x---{-|--Assigns a list of specifications to be juxtaposed horizontally in a visualization.--@-'toVegaLite'-    [ 'dataFromUrl' "data/driving.json" []-    , hConcat [ spec1, spec2 ]-    ]-@--}-hConcat :: [VLSpec] -> PropertySpec-hConcat specs = (VLHConcat, toJSON specs)---{-|--Assigns a list of specifications to superposed layers in a visualization.--@-'toVegaLite' ['dataFromUrl' "data/driving.json" [], layer [spec1, spec2]]-@--A complete example showing @layer@ in use:--@-let dvals = 'dataFromColumns' []-              . 'dataColumn' \"x\" ('Numbers' [1, 2, 3, 4, 5])-              . 'dataColumn' \"a\" ('Numbers' [28, 91, 43, 55, 81])-    enc = 'encoding'-             . 'position' 'X' ['PName' \"x\", 'PmType' 'Ordinal']-             . 'position' 'Y' ['PName' \"a\", 'PmType' 'Quantitative']-             . 'text' ['TName' \"a\", 'TmType' 'Nominal']--    in 'toVegaLite' [ dvals []-                  , enc []-                  , 'layer' [ 'asSpec' ['mark' 'Bar' []]-                          , 'asSpec' ['mark' 'Text' ['MdY' (-8)]]-                          ]-                  ]-@---}-layer :: [VLSpec] -> PropertySpec-layer specs = (VLLayer, toJSON specs)---{-|--Provides an optional name to be associated with the visualization.--@-'toVegaLite'-    [ 'name' \"PopGrowth\"-    , 'dataFromUrl' \"data/population.json\" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-name :: T.Text -> PropertySpec-name s = (VLName, toJSON s)---{-|--Set the padding around the visualization in pixel units. The way padding is-interpreted will depend on the 'autosize' properties. See the-<https://vega.github.io/vega-lite/docs/spec.html#top-level-specifications Vega-Lite documentation>-for details.--@-'toVegaLite'-    [ 'width' 500-    , 'padding' ('PEdges' 20 10 5 15)-    , 'dataFromUrl' "data/population.json" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-padding :: Padding -> PropertySpec-padding pad = (VLPadding, paddingSpec pad)---{-|--Define the fields that will be used to compose rows and columns of a-set of small multiples. This is used where the encoding of the-visualization in small multiples is largely identical, but the data-field used in each might vary. When a list of fields is identified-with @repeat@ you also need to define a full specification to apply to-each of those fields using 'asSpec'.--Unlike __faceting__, which creates multiple charts based on different values of a-single field, __repeating__ uses a different field for each chart.--See the-<https://vega.github.io/vega-lite/docs/repeat.html Vega-Lite documentation>-for further details.--@-'toVegaLite'-    [ 'repeat' ['ColumnFields' [\"Cat\", \"Dog\", \"Fish\"]]-    , 'specification' ('asSpec' spec)-    ]-@--See also 'repeatFlow'.---}--repeat :: [RepeatFields] -> PropertySpec-repeat fields = (VLRepeat, object (map repeatFieldsProperty fields))---{-|--Define the fields that will be used to compose a flow layout of a set of-small multiples. Used when the encoding is largely identical, but the data field-used in each might vary. When a list of fields is identified with @repeatFlow@ you also-need to define a full specification to apply to each of those fields using 'asSpec'.--Small multiples will be laid out from left to right, moving on to new rows only-if the number of plots exceeds an optional column limit (specified via 'columns').--@-'toVegaLite'-    [ 'repeatFlow' [ \"Cat\", \"Dog\", \"Fish\" ]-    , 'specification' ('asSpec' spec)-    ]-@--See also 'repeat'.--@since 0.4.0.0---}-repeatFlow :: [T.Text] -> PropertySpec-repeatFlow fields = (VLRepeat, toJSON fields)---{-|--Determine whether scales, axes or legends in composite views should-share channel encodings. This allows, for example, two different color-encodings to be created in a layered view, which otherwise by default-would share color channels between layers. Each resolution rule should-be in a tuple pairing the channel to which it applies and the rule-type.--@-let res = 'resolve'-            . 'resolution' ('RLegend' [('ChColor', 'Independent')])--in 'toVegaLite'-    [ 'dataFromUrl' \"data/movies.json\" []-    , 'vConcat' [heatSpec, barSpec]-    , res []-    ]-@--For more information see the-<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation>.--@-let dvals = 'dataFromColumns' []-              . 'dataColumn' "x" ('Numbers' [1, 2, 3, 4, 5])-              . 'dataColumn' "a" ('Numbers' [28, 91, 43, 55, 81])-              . 'dataColumn' "b" ('Numbers' [17, 22, 28, 30, 40])-    encBar = 'encoding'-               . 'position' 'X' ['PName' \"x\", 'PmType' 'Quantitative']-               . 'position' 'Y' ['PName' \"a\", 'PmType' 'Quantitative']-    specBar = 'asSpec' ['mark' 'Bar' [], encBar []]-    encLine = 'encoding'-                . 'position' 'X' ['PName' \"x\", 'PmType' 'Quantitative']-                . 'position' 'Y' ['PName' \"b\", 'PmType' 'Quantitative']-    specLine = 'asSpec' ['mark' 'Line' ['MColor' \"firebrick\"], encLine []]-    res = 'resolve'-            . 'resolution' ('RScale' [('ChY', 'Independent')])--in 'toVegaLite' [dvals [], res [], 'layer' [specBar, specLine]]-@---}-resolve :: [LabelledSpec] -> PropertySpec-resolve res = (VLResolve, object res)---{-|--Create a full selection specification from a list of selections. For details-see the-<https://vega.github.io/vega-lite/docs/selection.html Vega-Lite documentation>.--@-sel =-   'selection'-       . 'select' \"view\" 'Interval' ['BindScales'] []-       . 'select' \"myBrush\" 'Interval' []-       . 'select' \"myPaintbrush\" 'Multi' ['On' \"mouseover\", 'Nearest' True]-@---}--selection :: [LabelledSpec] -> PropertySpec-selection sels = (VLSelection, object sels)---{-|--Defines a specification object for use with faceted and repeated small multiples.--@-'toVegaLite'-    [ 'facet' [ 'RowBy' [ 'FName' \"Origin\", 'FmType' 'Nominal' ] ]-    , 'specification' spec-    ]-@--}-specification :: VLSpec -> PropertySpec-specification spec = (VLSpecification, spec)---{-|--Create a single transform from a list of transformation-specifications. Note that the order of transformations can be-important, especially if labels created with 'calculateAs',-'timeUnitAs', and 'binAs' are used in other transformations.  Using-the functional composition pipeline idiom (as example below) allows-you to provide the transformations in the order intended in a clear-manner.--@-'transform'-    . 'filter' ('FExpr' "datum.year == 2010")-    . 'calculateAs' "datum.sex == 2 ? \'Female\' : \'Male\'" "gender"-@--The supported transformations include: 'aggregate', 'binAs',-'calculateAs', 'impute', 'joinAggregate', 'lookup', 'lookupAs',-'flattenAs', 'foldAs', 'stack', 'timeUnitAs', and 'window'.---}--transform :: [LabelledSpec] -> PropertySpec-transform transforms =-  let js = if null transforms then A.Null else toJSON (map assemble transforms)--      -- use the same approach as Elm of encoding the spec, then decoding it,-      -- rather than inspecting the structure of the JSON-      ---      assemble :: LabelledSpec -> VLSpec-      assemble (str, val) =--        let dval = decode (encode val) :: Maybe A.Value-        in case str of-          "aggregate" ->-            case dval of-              Just (A.Array vs) | V.length vs == 2 -> object [ ("aggregate", vs V.! 0)-                                                             , ("groupby", vs V.! 1) ]-              _ -> A.Null--          "bin" ->-            case dval of-              Just (A.Array vs) | V.length vs == 3 -> object [ ("bin", vs V.! 0)-                                                             , ("field", vs V.! 1)-                                                             , ("as", vs V.! 2) ]-              _ -> A.Null--          "calculate" ->-            case dval of-              Just (A.Array vs) | V.length vs == 2 -> object [ ("calculate", vs V.! 0)-                                                             , ("as", vs V.! 1) ]-              _ -> A.Null---          "impute" ->-            case dval of-              Just (A.Array vs) | V.length vs == 8 ->-                                    let [imp, key, frameObj, keyValsObj, keyValsSequenceObj, methodObj, groupbyObj, valueObj] = V.toList vs--                                        addField _ A.Null = []-                                        addField f v = [(f, v)]--                                        ols = [ ("impute", imp)-                                              , ("key", key) ]-                                              <> addField "frame" frameObj-                                              <> addField "keyvals" keyValsObj-                                              <> addField "keyvals" keyValsSequenceObj-                                              <> addField "method" methodObj-                                              <> addField "groupby" groupbyObj-                                              <> addField "value" valueObj--                                    in object ols-              _ -> A.Null--          "lookup" ->-            case dval of-              Just (A.Array vs) | V.length vs == 4 -> object [ ("lookup", vs V.! 0)-                                                             , ("from",-                                                                object [ ("data", vs V.! 1)-                                                                       , ("key", vs V.! 2)-                                                                       , ("fields", vs V.! 3) ] )-                                                             ]-              _ -> A.Null--          "lookupAs" ->-            case dval of-              Just (A.Array vs) | V.length vs == 4 -> object [ ("lookup", vs V.! 0)-                                                             , ("from",-                                                                object [ ("data", vs V.! 1)-                                                                       , ("key", vs V.! 2) ] )-                                                             , ("as", vs V.! 3) ]-              _ -> A.Null--          "flattenAs" ->-            case dval of-              Just (A.Array vs) | V.length vs == 2 -> object [ ("flatten", vs V.! 0)-                                                             , ("as", vs V.! 1) ]-              _ -> A.Null--          "foldAs" ->-            case dval of-              Just (A.Array vs) | V.length vs == 3 -> object [ ("fold", vs V.! 0)-                                                             , ("as", toJSON [vs V.! 1, vs V.! 2]) ]-              _ -> A.Null--          "stack" ->-            case dval of-              Just (A.Array vs) | V.length vs == 6 ->-                                    let [field, grp, start, end, offsetObj, sortObj] = V.toList vs--                                        addField _ A.Null = []-                                        addField f v = [(f, v)]--                                        ols = [ ("stack", field)-                                              , ("groupby", grp)-                                              , ("as", toJSON [start, end]) ]-                                              <> addField "offset" offsetObj-                                              <> addField "sort" sortObj--                                    in object ols-              _ -> A.Null--          "timeUnit" ->-            case dval of-              Just (A.Array vs) | V.length vs == 3 -> object [ ("timeUnit", vs V.! 0)-                                                             , ("field", vs V.! 1)-                                                             , ("as", vs V.! 2) ]-              _ -> A.Null--          "window" ->-            case dval of-              Just (A.Array vs) | V.length vs == 5 ->-                                    let [winObj, frameObj, peersObj, groupbyObj, sortObj] = V.toList vs--                                        addField _ A.Null = []-                                        addField f v = [(f, v)]--                                        ols = [("window", winObj)]-                                              <> addField "frame" frameObj-                                              <> addField "ignorePeers" peersObj-                                              <> addField "groupby" groupbyObj-                                              <> addField "sort" sortObj--                                    in object ols-              _ -> A.Null--          "joinaggregate" ->-            case dval of-              Just (A.Array vs) | V.length vs == 5 ->-                                    let [joinObjs, frameObj, peersObj, groupbyObj, sortObj] = V.toList vs--                                        addField _ A.Null = []-                                        addField f v = [(f, v)]--                                        ols = [("joinaggregate", joinObjs)]-                                              <> addField "frame" frameObj-                                              <> addField "ignorePeers" peersObj-                                              <> addField "groupby" groupbyObj-                                              <> addField "sort" sortObj--                                    in object ols-              _ -> A.Null--          _ -> object [(str, val)]--    in (VLTransform, js)---{-|--Assigns a list of specifications to be juxtaposed vertically in a visualization.--@-'toVegaLite'-    [ 'dataFromUrl' "data/driving.json" []-    , 'vConcat' [ spec1, spec2 ]-    ]-@--}-vConcat :: [VLSpec] -> PropertySpec-vConcat specs = (VLVConcat, toJSON specs)---{-|--Override the default width of the visualization. If not specified the width-will be calculated based on the content of the visualization. See-'autosize' for customization of the content sizing relative to this-setting.--@-'toVegaLite'-    [ 'width' 500-    , 'dataFromUrl' "data/population.json" []-    , 'mark' 'Bar' []-    , enc []-    ]-@--}-width :: Double -> PropertySpec-width w = (VLWidth, toJSON w)----- | Properties for a window transform.------   @since 0.4.0.0--data WindowProperty-    = WFrame (Maybe Int) (Maybe Int)-      -- ^ Moving window for use by a window transform. When a number is-      --   given, via @Just@, then it indicates the offset from the current-      --   data object. A @Nothing@ indicates an un-bounded number of rows-      --   preceding or following the current data object.-    | WIgnorePeers Bool-      -- ^ Should the sliding window in a window transform ignore peer-      --   values (those considered identical by the sort criteria).-    | WGroupBy [T.Text]-      -- ^ The fields for partitioning data objects in a window transform-      --   into separate windows. If not specified, all points will be in a-      --   single group.-    | WSort [SortField]-      -- ^ Comparator for sorting data objects within a window transform.----- This is different to how Elm's VegaLite handles this (as of version 1.12.0)--- Helpers for windowPropertySpec---- allowNull :: A.ToJSON a => Maybe a -> VLSpec-allowNull :: Maybe Int -> VLSpec-allowNull (Just a) = toJSON a-allowNull Nothing = A.Null--wpFrame , wpIgnorePeers, wpGroupBy, wpSort :: WindowProperty -> Maybe VLSpec-wpFrame (WFrame m1 m2) = Just (toJSON [allowNull m1, allowNull m2])-wpFrame _ = Nothing--wpIgnorePeers (WIgnorePeers b) = Just (toJSON b)-wpIgnorePeers _ = Nothing--wpGroupBy (WGroupBy fs) = Just (toJSON fs)-wpGroupBy _ = Nothing--wpSort (WSort sfs) = Just (toJSON (map sortFieldSpec sfs))-wpSort _ = Nothing--windowPropertySpec :: [WindowProperty] -> [VLSpec]-windowPropertySpec wps =-  let frms = mapMaybe wpFrame wps-      ips = mapMaybe wpIgnorePeers wps-      gps = mapMaybe wpGroupBy wps-      sts = mapMaybe wpSort wps--      fromSpecs [spec] = spec-      fromSpecs _ = A.Null--  in map fromSpecs [frms, ips, gps, sts]----- | How should the field be sorted when performing a window transform.------   @since 0.4.00--data SortField-    = WAscending T.Text-    -- ^ Sort the field into ascending order.-    | WDescending T.Text-    -- ^ Sort the field into descending order.---sortFieldSpec :: SortField -> VLSpec-sortFieldSpec (WAscending f) = object [field_ f, order_ "ascending"]-sortFieldSpec (WDescending f) = object [field_ f, order_ "descending"]----- | Window transformations.------   @since 0.4.0.0--data Window-    = WAggregateOp Operation-      -- ^ An aggregrate operation to be used in a window transformation.-    | WOp WOperation-      -- ^ Window-specific operation to be used in a window transformation.-    | WParam Int-      -- ^ Numeric parameter for window-only operations that can be parameterised-      --   ('Ntile', 'Lag', 'Lead' and 'NthValue').-    | WField T.Text-      -- ^ Field for which to compute a window operation. Not needed for operations-      --   that do not apply to fields such as 'Count', 'Rank', and 'DenseRank'.---windowFieldProperty :: Window -> LabelledSpec-windowFieldProperty (WAggregateOp op) = "op" .= operationSpec op-windowFieldProperty (WOp op) = "op" .= wOperationLabel op-windowFieldProperty (WParam n) = "param" .= n-windowFieldProperty (WField f) = field_ f----- | Window-specific operation for transformations (for use with 'WOp').------   @since 0.4.0.0--data WOperation-    = RowNumber-      -- ^ Assign consecutive row number to values in a data object to be applied in a window transform.-    | Rank-      -- ^ Rank function to be applied in a window transform.-    | DenseRank-      -- ^ Dense rank function to be applied in a window transform.-    | PercentRank-      -- ^ Percentile of values in a sliding window to be applied in a window transform.-    | CumeDist-      -- ^ Cumulative distribution function to be applied in a window transform.-    | Ntile-      -- ^ Value preceding the current object in a sliding window to be applied in a window transform.-    | Lag-      -- ^ Value preceding the current object in a sliding window to be applied in a window transform.-    | Lead-      -- ^ Value following the current object in a sliding window to be applied in a window transform.-    | FirstValue-      -- ^ First value in a sliding window to be applied in a window transform.-    | LastValue-      -- ^ Last value in a sliding window to be applied in a window transform.-    | NthValue-      -- ^ Nth value in a sliding window to be applied in a window transform.---wOperationLabel :: WOperation -> T.Text-wOperationLabel RowNumber = "row_number"-wOperationLabel Rank = "rank"-wOperationLabel DenseRank = "dense_rank"-wOperationLabel PercentRank = "percent_rank"-wOperationLabel CumeDist = "cume_dist"-wOperationLabel Ntile = "ntile"-wOperationLabel Lag = "lag"-wOperationLabel Lead = "lead"-wOperationLabel FirstValue = "first_value"-wOperationLabel LastValue = "last_value"-wOperationLabel NthValue = "nth_value"---{-|--Defines a set of named aggregation transformations to be used when encoding-channels. This is useful when, for example, you wish to apply the same transformation-to a number of channels but do not want to define it each time. For further details-see the-<https://vega.github.io/vega-lite/docs/aggregate.html#aggregate-op-def Vega-Lite documentation>.--@-'transform'-    . 'aggregate'-        [ 'opAs' 'Min' "people" "lowerBound", 'opAs' 'Max' "people" "upperBound" ]-        [ "age" ]-@--See also 'joinAggregate'.---}-aggregate ::-  [VLSpec]-  -- ^ The named aggregation operations to apply.-  -> [T.Text]-  -- ^ The \"group by\" fields.-  -> BuildLabelledSpecs-aggregate ops groups ols =-  let ags = toJSON [toJSON ops, toJSON (map toJSON groups)]-  in ("aggregate", ags) : ols---{-|--Aggregation transformations to be used when encoding channels. Unlike-'aggregate', this transformation joins the results to the input data.-Can be helpful for creating derived values that combine raw data with some aggregate-measure, such as percentages of group totals. The first parameter is a list-of the named aggregation operations to apply. The second is a list of possible-window aggregate field properties, such as a field to group by when aggregating.-The third parameter is a list of transformations to which this is added.--@-'transform'-    . 'joinAggregate'-        [ 'opAs' 'Mean' "rating" "avYearRating" ]-        [ 'WGroupBy' [ "year" ] ]-    . 'filter' ('FExpr' "(datum.rating - datum.avYearRating) > 3"))-@--For details, see the-<https://vega.github.io/vega-lite/docs/joinaggregate.html Vega-Lite join aggregate documentation>.--See also 'aggregate'.--@since 0.4.0.0--}--joinAggregate ::-  [VLSpec]-  -> [WindowProperty]-  -> BuildLabelledSpecs-joinAggregate ops wProps ols =-  let ags = toJSON ops : windowPropertySpec wProps-  in ("joinaggregate", toJSON ags) : ols---{-|--Window transform for performing calculations over sorted groups of-data objects such as ranking, lead/lag analysis, running sums and averages.--The first parameter is a list of tuples each comprising a window transform field-definition and an output name. The second is the window transform definition.--@-'transform'-    . 'window' [ ( [ 'WAggregateOp' 'Sum', 'WField' "Time" ], "TotalTime" ) ]-             [ 'WFrame' Nothing Nothing ]-@--@since 0.4.0.0---}-window ::-  [([Window], T.Text)]-  -- ^ The window-transform definition and associated output name.-  -> [WindowProperty]-  -- ^ The window transform.-  -> BuildLabelledSpecs-window wss wProps ols =-  let args = toJSON wargs : windowPropertySpec wProps-      wargs = map winFieldDef wss-      winFieldDef (ws, out) = object ("as" .= out : map windowFieldProperty ws)-  in ("window" .= toJSON args) : ols---{-|--Randomly sample rows from a data source up to a given maximum.--For example, the following randomly samples 50 values from a sine curve:--@- dvals = 'dataSequenceAs' 0 13 0.001 \"x\"- trans = 'transform'-           . 'calculateAs' \"sin(datum.x)\" \"y\"-           . 'sample' 50-@--@since 0.4.0.0---}--sample :: Int -> BuildLabelledSpecs-sample maxSize ols = ("sample" .= maxSize) : ols---{-|--Create a named binning transformation that may be referenced in other Transformations-or encodings. See the-<https://vega.github.io/vega-lite/docs/bin.html Vega-Lite documentation> for-more details. Note that usually, direct binning within an encoding is preferred-over this form of bin transformation.--@-'transform'-    . 'binAs' [ 'MaxBins' 3 ] \"IMDB_Rating\" \"ratingGroup\"-@--}-binAs ::-  [BinProperty]-  -- ^ An empty list means that the default binning is used (that is, the-  --   @bin@ field will be set to @true@ in the Vega-Lite specification).-  -> T.Text-  -- ^ The field to bin.-  -> T.Text-  -- ^ The label for the binned data.-  -> BuildLabelledSpecs-binAs bProps field label ols =-  let js = if null bProps-           then [toJSON True, toJSON field, toJSON label]-           else [object (map binProperty bProps), toJSON field, toJSON label]- in ("bin" .= js) : ols---{-|--Creates a new data field based on calculations from existing fields and values.--See the <https://vega.github.io/vega-lite/docs/calculate.html Vega-Lite documentation>-for further details.--@-'transform' . 'calculateAs' "datum.sex == 2 ? \'F\' : \'M\'" "gender"-@--}-calculateAs ::-  T.Text-  -- ^ The calculation to perform, supporting the-  --   [Vega-Lite expression syntax](https://vega.github.io/vega/docs/expressions/).-  -> T.Text-  -- ^ The field to assign the new values.-  -> BuildLabelledSpecs-calculateAs expr label ols = ("calculate" .= [expr, label]) : ols---{-|--Encode a color channel.--@-'color' [ 'MName' \"Species\", 'MmType' 'Nominal' ] []-@--Encoding a color channel will generate a legend by default. To stop the legend-appearing, just supply an empty list of legend properties to 'MLegend':--@-'color' [ 'MName' \"Species\", 'MmType' 'Nominal', 'MLegend' [] ] []-@--}-color ::-  [MarkChannel]-  -- ^ The color-encoding options.-  -> BuildLabelledSpecs-color markProps ols = mchan_ "color" markProps : ols---{-|--Encodes a new facet to be arranged in columns. See the-<https://vega.github.io/vega-lite/docs/facet.html#facet-row-and-column-encoding-channels Vega-Lite column documentation>.--Note that when faceting, dimensions specified with 'width' and 'height'-refer to the individual faceted plots, not the overall visualization.--@-let dvals = 'dataFromUrl' \"crimeData.csv\"-    enc = 'encoding'-            . 'position' 'X' ['PName' \"month\", 'PmType' 'Temporal']-            . 'position' 'Y' ['PName' \"reportedCrimes\", 'PmType' 'Quantitative'-                         , 'PAggregate' 'Sum']-            . 'column' ['FName' \"crimeType\", 'FmType' 'Nominal']--    in 'toVegaLite' ['width' 100, dvals [], 'mark' 'Bar' [], enc [] ]-@--}-column ::-  [FacetChannel]-  -- ^ The list of properties that define the faceting channel. At a minimum-  --   this should include the data field ('FName') and its measurement type-  --   ('FmType').-  -> BuildLabelledSpecs-column fFields ols =-  ("column" .= object (map facetChannelProperty fFields)) : ols---{-|--The maximum number of columns to include in a view composition flow-layout. If the number of faceted small multiples exceeds this number,-flow moves to the next row.  Only applies to flow layouts generated by-'vlConcat', 'facetFlow', and 'repeatFlow'.--@since 0.4.0.0---}--columns ::-  Natural-  -- ^ A value of 0 means that a single row will be used (which is also-  --   the default behavior).-  -> PropertySpec-columns cols = (VLColumns, toJSON cols)---{-|--Defines a single configuration option to be applied globally across the visualization.-The first parameter identifies the type of configuration, the second a list of previous-configurations to which this one may be added.--@-'configuration' ('Axis' [ 'DomainWidth' 4 ]) []-@--}-configuration :: ConfigurationProperty -> BuildLabelledSpecs-configuration cfg ols = configProperty cfg : ols---{-|--Encode a \"level of detail\" channel. This provides a way of grouping by a field-but unlike, say 'color', all groups have the same visual properties.--See the-<https://vega.github.io/vega-lite/docs/encoding.html#detail Vega-Lite documentation>-for details.--@-'detail' ['DName' \"Species\", 'DmType' 'Nominal'] []-@--}-detail ::-  [DetailChannel]-  -- ^ The field to group.-  -> BuildLabelledSpecs-detail detailProps ols =-    ("detail" .= object (map detailChannelProperty detailProps)) : ols---{-|--Encode a fill channel. This acts in a similar way to encoding by 'color' but-only affects the interior of closed shapes. The first parameter is a list of mark-channel properties that characterise the way a data field is encoded by fill.-The second parameter is a list of any previous channels to which this fill channel-should be added.--@-'fill' [ 'MName' \"Species\", 'MmType' 'Nominal' ] []-@--Note that if both @fill@ and 'color' encodings are specified, @fill@ takes precedence.---}--fill :: [MarkChannel] -> BuildLabelledSpecs-fill markProps ols = mchan_ "fill" markProps : ols---{-|--Encode a fill opacity channel. This acts in a similar way to encoding by 'opacity'-but only affects the interior of closed shapes. If both @fillOpacity@ and 'opacity'-encodings are specified, @fillOpacity@ takes precedence.--See also 'fill'.--@since 0.4.0.0--}--fillOpacity :: [MarkChannel] -> BuildLabelledSpecs-fillOpacity markProps ols = mchan_ "fillOpacity" markProps : ols---{-|--Adds the given filter operation a list of transformations that may be applied-to a channel or field.--@-'transform'-    . 'filter' ('FEqual' \"Animal\" ('Str' \"Cat\"))-@--Filter operations can combine selections and data predicates with 'BooleanOp'-expressions (and as of @0.4.0.0@, 'FilterOp' and 'FilterOpTrans'-can be used to lift the 'Filter' type into boolean expressions):--@-'transform'-    . 'filter' ('FCompose' ('And' ('Expr' "datum.Weight_in_lbs > 3000") ('Selection' "brush")))-@--The [Vega-Lite expression documentation](https://vega.github.io/vega/docs/expressions/)-describes the supported format (e.g. the requirement to precede column names-with @"datum."@).---}-filter :: Filter -> BuildLabelledSpecs-filter f ols = ("filter" .= filterSpec f) : ols----{-|--Map array-valued fields to a set of individual data objects, one per array entry.--See also 'flattenAs'.--@since 0.4.0.0---}--flatten :: [T.Text] -> BuildLabelledSpecs-flatten fields ols = ("flatten" .= fields) : ols---{-|--Similar to 'flatten' but allows the new output fields to be named.--@since 0.4.0.0---}--flattenAs ::-  [T.Text]-  -> [T.Text]-  -- ^ The names of the output fields.-  -> BuildLabelledSpecs-flattenAs fields names ols = ("flattenAs" .= [fields, names]) : ols---{-|--Perform a /gather/ operation to /tidy/ a table. Collapse multiple data fields-into two new data fields: @key@ containing the original data field names and @value@-containing the corresponding data values. This performs the same function as the-<https://tidyr.tidyverse.org/dev/articles/pivot.html pivot_longer> and-<https://tidyr.tidyverse.org/reference/gather.html gather>-operations in the R tidyverse.--See also 'foldAs'.--@-dvals =-    'dataFromColumns' []-        . 'dataColumn' \"city\" ('Strings' [ \"Bristol\", \"Sheffield\", \"Glasgow\" ])-        . 'dataColumn' \"temp2017\" ('Numbers' [ 12, 11, 7 ])-        . 'dataColumn' \"temp2018\" ('Numbers' [ 14, 13, 10 ])--trans =-    'transform'-        . 'fold' [ \"temp2017\", \"temp2018\" ]--enc =-    'encoding'-        . 'position' 'X' [ 'PName' \"key\", 'PmType' 'Nominal' ]-        . 'position' 'Y' [ 'PName' \"city\", 'PmType' 'Nominal' ]-        . 'size' [ 'MName' \"value\", 'MmType' 'Quantitative' ]-@--@since 0.4.0.0--}--fold :: [T.Text] -> BuildLabelledSpecs-fold fields ols = ("fold" .= fields) : ols---{-|--A 'fold' where the @key@ and @value@ fields can be renamed.--@since 0.4.0.0---}--foldAs ::-  [T.Text]-  -> T.Text-  -- ^ The name for the @key@ field.-  -> T.Text-  -- ^ The name for the @value@ field.-  -> BuildLabelledSpecs-foldAs fields keyName valName ols =-  ("foldAs" .= [toJSON fields, fromT keyName, fromT valName]) : ols---{-|--Encode a hyperlink channel.--@-'encoding'-  . 'hyperlink' [ 'HName' \"Species\", 'HmType' 'Nominal' ]-@--@-'encoding'-  . 'hyperlink' [ 'HString' \"http://www.imdb.com\" ]-@--For further details see the-<https://vega.github.io/vega-lite/docs/encoding.html#href Vega-Lite documentation>.---}-hyperlink ::-  [HyperlinkChannel]-  -- ^ The properties for the hyperlink channel.-  -> BuildLabelledSpecs-hyperlink hyperProps ols =-  ("href" .= object (concatMap hyperlinkChannelProperty hyperProps)) : ols---{-|--Perform a lookup of named fields between two data sources. This allows-you to find values in one data source based on the values in another-(like a relational join).--Unlike 'lookupAs', this function will only return the specific fields-named in the fourth parameter. If you wish to return the entire set of-fields in the secondary data source as a single object, use-'lookupAs'.--See the <https://vega.github.io/vega-lite/docs/lookup.html Vega-Lite documentation>-for further details.--The following would return the values in the @age@ and @height@ fields from-@lookup_people.csv@ for all rows where the value in the @name@ column in that-file matches the value of @person@ in the primary data source.--@-trans = 'transform'-          . 'lookup' \"person\" ('dataFromUrl' \"data/lookup_people.csv\" []) \"name\" [\"age\", \"height\"]-@--}-lookup ::-  T.Text-  -- ^ The field in the primary data structure acting as the key.-  -> Data-  -- ^ The secondary data source (e.g. the return from the data-generating-  --   functions such as 'dataFromUrl').-  -> T.Text-  -- ^ The name of the field in the secondary data source to match against-  --   the primary key.-  -> [T.Text]-  -- ^ The list of fields to store when the keys match.-  -> BuildLabelledSpecs-lookup key1 (_, spec) key2 fields ols =-  let js = [toJSON key1, spec, toJSON key2, toJSON (map toJSON fields)]-  in ("lookup" .= js) : ols---{-|--Perform an object lookup between two data sources. This allows you to-find values in one data source based on the values in another (like a-relational join).  Unlike 'lookup', this function returns the entire-set of field values from the secondary data source when keys-match. Those fields are stored as an object with the name provided in-the fourth parameter.--In the following example, @personDetails@ would reference all the-field values in @lookup_people.csv@ for each row where the value in-the @name@ column in that file matches the value of @person@ in the-primary data source.--@-'transform'-    . 'lookupAs' "person" ('dataFromUrl' "data/lookup_people.csv" []) "name" "personDetails"-@--If the data contained columns called @age@ and @height@ then they would-then be accessed as @personDetails.age@ and @personDetails.height@ - for-example:--@-'encoding'-  . 'position' X ['PName' "personDetails.age", 'PmType' 'Temporal', 'PTimeUnit' 'Year', 'PTitle' \"Age\"]-  . 'position' Y ['PName' "personDetails.height", 'PmType' 'Quantitative', 'PTitle' \"Height\"]-@--See the-<https://vega.github.io/vega-lite/docs/lookup.html Vega-Lite documentation>-for further details.---}-lookupAs ::-  T.Text-  -- ^ The field in the primary data structure acting as the key.-  -> Data-  -- ^ The secondary data source (e.g. the return from the data-generating-  --   functions such as 'dataFromUrl').-  -> T.Text-  -- ^ The name of the field in the secondary data source to match against-  --   the primary key.-  -> T.Text-  -- ^ The field name for the new data.-  -> BuildLabelledSpecs-lookupAs key1 (_, spec) key2 asName ols =-  ("lookupAs" .= [toJSON key1, spec, toJSON key2, toJSON asName]) : ols----- | This is used with `impute` and `PImpute`.------   @since 0.4.0.0--data ImputeProperty-    = ImFrame (Maybe Int) (Maybe Int)-      -- ^ 1d window over which data imputation values are generated. The two-      --   parameters should either be @Just@ a number indicating the offset from the current-      --   data object, or @Nothing@ to indicate unbounded rows preceding or following the-      --   current data object.-    | ImKeyVals DataValues-      -- ^ Key values to be considered for imputation.-    | ImKeyValSequence Double Double Double-      -- ^ Key values to be considered for imputation as a sequence of numbers between-      --   a start (first parameter), to less than an end (second parameter) in steps of-      --   the third parameter.-    | ImMethod ImMethod-      -- ^ How is the imputed value constructed.-      ---      --   When using @ImMethod 'ImValue'@, the replacement value is-      --   set with 'ImNewValue'.-    | ImGroupBy [T.Text]-      -- ^ Allow imputing of missing values on a per-group basis. For use with the impute-      --   transform only and not a channel encoding.-    | ImNewValue DataValue-      -- ^ The replacement value (when using @ImMethod 'ImValue'@).---imputeProperty :: ImputeProperty -> LabelledSpec-imputeProperty (ImFrame m1 m2) = "frame" .= map allowNull [m1, m2]-imputeProperty (ImKeyVals dVals) = "keyvals" .= dataValuesSpecs dVals-imputeProperty (ImKeyValSequence start stop step) =-  "keyvals" .= object ["start" .= start, "stop" .= stop, "step" .= step]-imputeProperty (ImMethod method) = "method" .= imMethodLabel method-imputeProperty (ImNewValue dVal) = "value" .= dataValueSpec dVal-imputeProperty (ImGroupBy _) = "groupby" .= A.Null---imputePropertySpecFrame, imputePropertySpecKeyVals,-  imputePropertySpecKeyValSequence, imputePropertySpecGroupBy,-  imputePropertySpecMethod, imputePropertySpecValue :: ImputeProperty -> Maybe VLSpec--imputePropertySpecFrame (ImFrame m1 m2) = Just (toJSON (map allowNull [m1, m2]))-imputePropertySpecFrame _ = Nothing--imputePropertySpecKeyVals (ImKeyVals dVals) = Just (toJSON (dataValuesSpecs dVals))-imputePropertySpecKeyVals _ = Nothing--imputePropertySpecKeyValSequence (ImKeyValSequence start stop step) =-  let obj = ["start" .= start, "stop" .= stop, "step" .= step]-  in Just (object obj)-imputePropertySpecKeyValSequence _ = Nothing--imputePropertySpecGroupBy (ImGroupBy fields) = Just (toJSON fields)-imputePropertySpecGroupBy _ = Nothing--imputePropertySpecMethod (ImMethod method) = Just (toJSON (imMethodLabel method))-imputePropertySpecMethod _ = Nothing--imputePropertySpecValue (ImNewValue dVal) = Just (dataValueSpec dVal)-imputePropertySpecValue _ = Nothing------ | Imputation method to use when replacing values.------   @since 0.4.0.0--data ImMethod-  = ImMin-    -- ^ Use the minimum value.-  | ImMax-    -- ^ Use the maximum value.-  | ImMean-    -- ^ Use the mean value.-  | ImMedian-    -- ^ Use the median value.-  | ImValue-    -- ^ Use a replacement value (set with @ImNewValue@).---imMethodLabel :: ImMethod -> T.Text-imMethodLabel ImMin = "min"-imMethodLabel ImMax = "max"-imMethodLabel ImMean = "mean"-imMethodLabel ImMedian = "median"-imMethodLabel ImValue = "value"--{-|--Impute missing data values.--The following example creates a value for @b@, set to the-mean of existing @b@ values with @c=1@, for the \"missing\" coordinate-of (@a=30@, @c=1@):--@-let dvals = 'dataFromColumns' []-              . 'dataColumn' "a" ('Numbers' [0, 0, 10, 10, 20, 20, 30])-              . 'dataColumn' "b" ('Numbers' [28, 91, 43, 55, 81, 53, 19])-              . 'dataColumn' "c" ('Numbers' [0, 1, 0, 1, 0, 1, 0])--    trans = 'transform'-              . 'impute' "b" "a" ['ImMethod' 'ImMean', 'ImGroupBy' ["c"]]--    enc = 'encoding'-            . 'position' 'X' ['PName' \"a\", 'PmType' 'Quantitative']-            . 'position' 'Y' ['PName' \"b\", 'PmType' 'Quantitative']-            . 'color' ['MName' \"c\", 'MmType' 'Nominal']--    in 'toVegaLite' [dvals [], trans [], enc [], 'mark' 'Line' []]-@--@since 0.4.0.0--}--impute ::-  T.Text-  -- ^ The data field to process.-  -> T.Text-  -- ^ The key field to uniquely identify data objects within a group.-  -> [ImputeProperty]-  -- ^ Define how the imputation works.-  -> BuildLabelledSpecs-impute fields key imProps ols =-  let ags = [ fromT fields, fromT key-            , toSpec (mapMaybe imputePropertySpecFrame imProps)-            , toSpec (mapMaybe imputePropertySpecKeyVals imProps)-            , toSpec (mapMaybe imputePropertySpecKeyValSequence imProps)-            , toSpec (mapMaybe imputePropertySpecMethod imProps)-            , toSpec (mapMaybe imputePropertySpecGroupBy imProps)-            , toSpec (mapMaybe imputePropertySpecValue imProps) ]--      toSpec [x] = x-      toSpec _ = A.Null--  in ("impute", toJSON ags) : ols---{-|--Encode an opacity channel. The first parameter is a list of mark-channel properties that characterise the way a data field is encoded-by opacity. The second parameter is a list of any previous channels to-which this opacity channel should be added.--@-'opacity' [ 'MName' \"Age\", 'MmType' 'Quantitative' ] []-@--See also 'fillOpacity'.---}--opacity :: [MarkChannel] -> BuildLabelledSpecs-opacity markProps ols = mchan_ "opacity" markProps : ols---{-|--Encode an order channel.--@-enc =-    'encoding'-        . 'position' 'X' [ 'PName' "miles", 'PmType' 'Quantitative' ]-        . 'position' 'Y' [ 'PName' "gas", 'PmType' 'Quantitative' ]-        . 'order' [ 'OName' "year", 'OmType' 'Temporal', 'OSort' ['Descending'] ]-@--}-order ::-  [OrderChannel]-  -- ^ The order-encoding options.-  -> BuildLabelledSpecs-order oDefs ols =-  ("order" .= object (map orderChannelProperty oDefs)) : ols---{-|--Encode a position channel.--@-enc =-    'encoding'-      . 'position' 'X' [ 'PName' \"Animal\", 'PmType' 'Ordinal' ]-@--Encoding by position will generate an axis by default. To prevent the axis from-appearing, simply provide an empty list of axis properties to 'PAxis':--@-enc =-    'encoding'-      . 'position' 'X' [ 'PName' \"Animal\", 'PmType' 'Ordinal', 'PAxis' [] ]-@--}-position ::-  Position-  -- ^ The channel to encode.-  -> [PositionChannel]-  -- ^ The options for the channel; this will usually include the name ('PName')-  --    and measurement type ('PmType'), but can be a reference to a row or-  --    column repeat field.-  -> BuildLabelledSpecs-position pos pDefs ols =-  let defs = object (map positionChannelProperty pDefs)-  in (positionLabel pos, defs) : ols---{-|--Define a single resolution option to be applied when scales, axes or legends-in composite views share channel encodings. This allows, for example, two different-color encodings to be created in a layered view, which otherwise by default would-share color channels between layers. Each resolution rule should be in a tuple-pairing the channel to which it applies and the rule type.--@-'resolve'-    . resolution ('RScale' [ ( 'ChY', 'Independent' ) ])-@--}-resolution :: Resolve -> BuildLabelledSpecs-resolution res ols = resolveProperty res : ols---{-|--Encode a new facet to be arranged in rows.--See the-<https://vega.github.io/vega-lite/docs/facet.html#facet-row-and-column-encoding-channels Vega-Lite row documentation>.--Note that when faceting, dimensions specified with 'width' and 'height'-refer to the individual faceted plots, not the whole visualization.--@-let dvals = 'dataFromUrl' \"crimeData.csv\"-    enc = 'encoding'-            . 'position' 'X' ['PName' \"month\", 'PmType' 'Temporal']-            . 'position' 'Y' ['PName' \"reportedCrimes\"-                         , 'PmType' 'Quantitative'-                         , 'PAggregate' 'Sum'-                         , 'PAxis' ['AxNoTitle']-                         ]-            . 'row' ['FName' \"crimeType\", 'FmType' 'Nominal']--in 'toVegaLite' ['height' 80, dvals [], 'mark' 'Bar' [], enc []]-@---}-row ::-  [FacetChannel]-  -- ^ The facet properties for the channel; this should include the name of-  --   the field ('FName') and its measurement type ('FmType').-  -> BuildLabelledSpecs-row fFields ols = ("row" .= object (map facetChannelProperty fFields)) : ols---{-|--Create a single named selection that may be applied to a data query or transformation.--@-sel =-    'selection'-        . 'select' "view" 'Interval' [ 'BindScales' ] []-        . 'select' "myBrush" 'Interval' []-        . 'select' "myPaintbrush" 'Multi' [ 'On' "mouseover", 'Nearest' True ]-@---}-select ::-  T.Text-  -- ^ The name given to the selection.-  -> Selection-  -- ^ The type of the selection.-  -> [SelectionProperty]-  -- ^ What options are applied to the selection.-  -> BuildLabelledSpecs-select nme sType options ols =-    let selProps = ("type" .= selectionLabel sType) : map selectionProperty options-    in (nme .= object selProps) : ols---{-|--Encode a shape channel.--@-'shape' [ 'MName' \"Species\", 'MmType' 'Nominal' ] []-@--}-shape ::-  [MarkChannel]-  -- ^ What data values are used to control the shape parameters of the mark.-  -> BuildLabelledSpecs-shape markProps ols = mchan_ "shape" markProps : ols---{-|--Encode a size channel.--@-'size' [ 'MName' \"Age\", 'MmType' 'Quantitative' ] []-@--}-size ::-  [MarkChannel]-  -- ^ What data values are used to control the size parameters of the mark.-  -> BuildLabelledSpecs-size markProps ols = mchan_ "size" markProps : ols---{-|--Encode a stroke channel. This acts in a similar way to encoding by 'color' but-only affects the exterior boundary of marks.--@-'stroke' [ 'MName' \"Species\", 'MmType' 'Nominal' ] []-@--Note that if both @stroke@ and 'color' encodings are specified, @stroke@ takes-precedence.---}-stroke ::-  [MarkChannel]-  -- ^ What data values are used to control the stoke parameters of the mark.-  -> BuildLabelledSpecs-stroke markProps ols = mchan_ "stroke" markProps : ols---{-|--Encode a stroke opacity channel. This acts in a similar way to encoding by-'opacity' but only affects the exterior boundary of marks. If both 'opacity' and-@strokeOpacity@ are specified, @strokeOpacity@ takes precedence for stroke encoding.--@since 0.4.0.0---}--strokeOpacity ::-  [MarkChannel]-  -- ^ What data values are used to control the stoke opacity parameters of the mark.-  -> BuildLabelledSpecs-strokeOpacity markProps ols = mchan_ "strokeOpacity" markProps : ols---{-|--Encode a stroke width channel.--@since 0.4.0.0---}--strokeWidth ::-  [MarkChannel]-  -- ^ What data values are used to control the stoke width parameters of the mark.-  -> BuildLabelledSpecs-strokeWidth markProps ols = mchan_ "strokeWidth" markProps : ols---{-|--Encode a text channel. See the-<https://vega.github.io/vega-lite/docs/encoding.html#text Vega-Lite documentation>-for further details on the text and tooltip channels and-<https://vega.github.io/vega-lite/docs/format.html Vega-Lite formatting documentation>-for formatting the appearance of the text.--@-'encoding'-    . 'position' 'X' [ 'PName' "miles", 'PmType' 'Quantitative' ]-    . 'position' 'Y' [ 'PName' "gas", 'PmType' 'Quantitative' ]-    . 'text' [ 'TName' "miles", 'TmType' 'Quantitative' ]-@--}-text ::-  [TextChannel]-  -- ^ What data values are used to control the text parameters.-  -> BuildLabelledSpecs-text tDefs ols =-  ("text" .= object (concatMap textChannelProperty tDefs)) : ols---{-|--Creates a new data field based on the given temporal binning. Unlike the-direct encoding binning, this transformation is named and so can be referred-to in multiple encodings. Note though that usually it is easer to apply the temporal-binning directly as part of the encoding as this will automatically format the-temporal axis. See the-<https://vega.github.io/vega-lite/docs/timeunit.html#transform Vega-Lite documentation>-for further details.--The following example takes a temporal dataset and encodes daily totals from it-grouping by month:--@-trans = 'transform' . 'timeUnitAs' 'Month' \"date\" \"monthly\"--enc = 'encoding'-        . 'position' 'X' [ 'PName' \"date\", 'PmType' 'Temporal', 'PTimeUnit' 'Day' ]-        . 'position' 'Y' [ 'PAggregate' 'Sum', 'PmType' 'Quantitative' ]-        . 'detail' [ 'DName' \"monthly\", 'DmType' 'Temporal' ]-@--}-timeUnitAs ::-  TimeUnit-  -- ^ The width of each bin.-  -> T.Text-  -- ^ The field to bin.-  -> T.Text-  -- ^ The name of the binned data created by this routine.-  -> BuildLabelledSpecs-timeUnitAs tu field label ols =-  ("timeUnit" .= [timeUnitLabel tu, field, label]) : ols---{-|--Encode a tooltip channel. See the-<https://vega.github.io/vega-lite/docs/encoding.html#text Vega-Lite documentation>-for further details on the text and tooltip channels and-<https://vega.github.io/vega-lite/docs/format.html Vega-Lite formatting documentation>-for formatting the appearance of the text.--@-enc = 'encoding'-        . 'position' 'X' [ 'PName' \"Horsepower\", 'PmType' 'Quantitative' ]-        . 'position' 'Y' [ 'PName' \"Miles_per_Gallon\", 'PmType' 'Quantitative' ]-        . 'tooltip' [ 'TName' \"Year\", 'TmType' 'Temporal', 'TFormat' "%Y" ]-@--To encode multiple tooltip values with a mark, use 'tooltips'.---}-tooltip ::-  [TextChannel]-  -- ^ The properties for the channel.-  -> BuildLabelledSpecs-tooltip tDefs ols =-  ("tooltip" .= object (concatMap textChannelProperty tDefs)) : ols--{-|--Encode a tooltip channel using multiple data fields.--@since 0.3.0.0--@-'encoding'-    . 'position' 'X' [ 'PName' \"Horsepower\", 'PmType' 'Quantitative' ]-    . 'position' 'Y' [ 'PName' \"Miles_per_Gallon\", 'PmType' 'Quantitative' ]-    . 'tooltips' [ [ 'TName' \"Year\",  'TmType' 'Temporal', 'TFormat' "%Y" ]-               , [ 'TName' \"Month\", 'TmType' 'Temporal', 'TFormat' "%Y" ] ]-@--}-tooltips ::-  [[TextChannel]]-  -- ^ A separate list of properties for each channel.-  -> BuildLabelledSpecs-tooltips tDefs ols =-  ("tooltip" .= toJSON (map (object . concatMap textChannelProperty) tDefs)) : ols----- | This is used with 'MTooltip'.------   @since 0.4.0.0--data TooltipContent-  = TTEncoding-    -- ^ Tooltips are generated by the encoding (this is the default).-    ---    --   For example:-    ---    --   @'mark' 'Circle' ['MTooltip' 'TTEncoding']@-  | TTData-    -- ^ Tooltips are generated by all fields in the underlying data.-    ---    --   For example:-    ---    --   @'mark' 'Circle' ['MTooltip' 'TTData']@-  | TTNone-    -- ^ Disable tooltips.-    ---    --   For example:-    ---    --   @'mark' 'Circle' ['MTooltip' 'TTNone']@----- Note that TTNone is special cased by markProperty-ttContentLabel :: TooltipContent -> T.Text-ttContentLabel TTEncoding = "encoding"-ttContentLabel TTData = "data"-ttContentLabel TTNone = "null"+{-|+Module      : Graphics.Vega.VegaLite+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings, TupleSections++This is a port of the+<http://package.elm-lang.org/packages/gicentre/elm-vegalite/latest Elm Vega Lite module>,+written by Jo Wood of the giCentre at the City+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>).++Although this is based on the Elm module, there are differences, such+as using type constructors rather than functions for many properties -+such as @'VL.PName' \"HorsePower\"@ rather than @pName \"HorsePower\"@ -+and the return value of 'VL.toVegaLite'. The intention is to keep close+to the Elm module, but it is more a guide than an absolute+requirement!++Please see "Graphics.Vega.Tutorials.VegaLite" for an introduction+to using @hvega@ to create visualizations.++== Example++Note that this module exports several symbols that are exported+by the Prelude, such as 'VL.filter', 'VL.lookup',+and 'VL.repeat'; to avoid name clashes it's therefore advised+to either import the module qualified, for example:++@+import qualified Graphics.Vega.VegaLite as VL+@++or to hide the clashing names explicitly:++@+import Prelude hiding (filter, lookup, repeat)+@++In the following example, we'll assume the latter.++Let's say we have the following plot declaration in a module:++@+\{\-\# language OverloadedStrings \#\-\}++vl1 =+  let desc = "A very exciting bar chart"++      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)]++      barOpts = ['VL.MOpacity' 0.4, 'VL.MColor' "teal"]++      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']++  in 'VL.toVegaLite' ['VL.description' desc, 'VL.background' "white"+                , dat [], 'VL.mark' 'VL.Bar' barOpts, enc []]+@++We can inspect how the encoded JSON looks like in an GHCi session:++@+> '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\"}"+@++The produced JSON can then be processed with vega-lite, which renders the following image:++<<images/example.png>>++which can also be+<https://vega.github.io/editor/#/url/vega-lite/N4KABGBEC2CGBOBrSAuMxIGMD2Abb8qUALgKay6QA0U2ADrJgJbECeRADAHQAsNkbOqSKQARgkgBfKuCgATWMVhFQECJABuFAK6kAzkQDastekh6l8YiIBMHAIz2AtBwDMTmwFZqUHNoB21mg2rtImahgWCEFQdo4uPC42PljYATE8nmGmEJGWMZBxzhyJ9sn8foFEoeEAujKmkABmBHAxGAzwesJoedEiCmQoAOQApACaTqPQU3LDUpKy2VAAJHqYABakcCIbxMR0eigA9McapADmsFwXLBvaolxM2MfrW3Bnl7BOuCykZ64uAArPTYfzUWSQUj+HByJj+C4qcKQAAeSJyUCaTFIuDkIiiVghGIErCEIjI0DoBAoRJykFgKKYBl6AhYuB6UAAkjDSHRiM9-GBBsJFqZlup2CysTi8WhUukUoIOZAAI7aWCBFiKJjnKRLBpQcSYRAXeBpfyyqAAdw2f1pkDk+kw8CYfIFIgAgmBzvBWGBSCjmPyEWBxPAwJt+gbUv4sYjeotJEA displayed in the Vega Editor>.++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+specification (there are also functions which provide more control over+the embedding).++-}++module Graphics.Vega.VegaLite+       (+         -- * Creating a Vega-Lite Specification++         VL.toVegaLite+       , VL.toVegaLiteSchema+       , VL.vlSchema2, VL.vlSchema3, VL.vlSchema4, VL.vlSchema+       , VL.fromVL+       , VL.VLProperty(..)+       , VL.VLSpec+       , VL.VegaLite+       , VL.PropertySpec+       , VL.LabelledSpec+       , VL.EncodingSpec+       , VL.toEncodingSpec+       , VL.fromEncodingSpec+       , VL.TransformSpec+       , VL.toTransformSpec+       , VL.fromTransformSpec+       , VL.ResolveSpec+       , VL.toResolveSpec+       , VL.fromResolveSpec+       , VL.SelectSpec+       , VL.toSelectSpec+       , VL.fromSelectSpec+       , VL.ConfigureSpec+       , VL.toConfigureSpec+       , VL.fromConfigureSpec+       , VL.BuildEncodingSpecs+       , VL.BuildTransformSpecs+       , VL.BuildResolveSpecs+       , VL.BuildSelectSpecs+       , VL.BuildConfigureSpecs+       , VL.Angle+       , VL.Color+       , VL.DashStyle+       , VL.DashOffset+       , VL.FieldName+       , VL.GradientCoord+       , VL.GradientStops+       , VL.Opacity+       , VL.SelectionLabel+       , VL.VegaExpr+       , VL.ZIndex+       , VL.toHtml+       , VL.toHtmlFile+       , VL.toHtmlWith+       , VL.toHtmlFileWith++         -- * Creating the Data Specification+         --+         -- $dataspec++       , VL.dataFromUrl+       , VL.dataFromColumns+       , VL.dataFromRows+       , VL.dataFromJson+       , VL.dataFromSource+       , VL.dataName+       , VL.datasets+       , VL.dataColumn+       , VL.dataRow+       , VL.noData+       , VL.Data+       , VL.DataColumn+       , VL.DataRow++         -- ** Geographic Data++       , VL.geometry+       , VL.geoFeatureCollection+       , VL.geometryCollection+       , VL.Geometry(..)++       -- ** Data Generators+       --+       -- $datagen++       , VL.dataSequence+       , VL.dataSequenceAs+       , VL.sphere+       , VL.graticule+       , VL.GraticuleProperty(..)++       -- ** Formatting Input Data+       --+       -- $dataformat++       , VL.Format(..)+       , VL.DataType(..)++         -- * Creating the Transform Specification+         --+         -- $transform++       , VL.transform++         -- ** Map Projections+         --+         -- $projections++       , VL.projection+       , VL.ProjectionProperty(..)+       , VL.Projection(..)+       , VL.ClipRect(..)++         -- ** Aggregation+         --+         -- $aggregation++       , VL.aggregate+       , VL.joinAggregate+       , VL.opAs+       , VL.timeUnitAs+       , VL.Operation(..)++         -- ** Binning+         --+         -- $binning++       , VL.binAs+       , VL.BinProperty(..)++         -- ** Stacking+         --+         -- $stacking++       , VL.stack+       , VL.StackProperty(..)+       , VL.StackOffset(..)++         -- ** Data Calculation+         --+         -- $calculate++       , VL.calculateAs++         -- ** Filtering+         --+         -- $filtering++       , VL.filter+       , VL.Filter(..)+       , VL.FilterRange(..)++         -- ** Flattening+         --+         -- $flattening++       , VL.flatten+       , VL.flattenAs++         -- ** Folding and Pivoting+         --+         -- $foldpivot++       , VL.fold+       , VL.foldAs+       , VL.pivot+       , VL.PivotProperty(..)++         -- ** Relational Joining (lookup)+         --+         -- $joining++       , VL.lookup+       , VL.lookupSelection+       , VL.LookupFields(..)+       , VL.lookupAs++         -- ** Data Imputation+         --+         -- $imputation++       , VL.impute+       , VL.ImputeProperty(..)+       , VL.ImMethod(..)++         -- ** Data sampling+         --+         -- $sampling++       , VL.sample++         -- ** Density Estimation+         --+         -- $density++       , VL.density+       , VL.DensityProperty(..)++         -- ** Loess Trend Calculation+         --+         -- $loess++       , VL.loess+       , VL.LoessProperty(..)++         -- ** Regression Calculation+         --+         -- $regression++       , VL.regression+       , VL.RegressionProperty(..)+       , VL.RegressionMethod(..)++         -- ** Qualtile Calculation+         --+         -- $quantile++       , VL.quantile+       , VL.QuantileProperty(..)++         -- ** Window Transformations+         --+         -- $window++       , VL.window+       , VL.Window(..)+       , VL.WOperation(..)+       , VL.WindowProperty(..)++         -- * Creating the Mark Specification+         --+         -- $markspec++       , VL.mark+       , VL.Mark(..)++         -- ** Mark properties+         --+         -- $markproperties++       , VL.MarkProperty(..)+       , VL.StrokeCap(..)+       , VL.StrokeJoin(..)++         -- *** Used by Mark Properties++       , VL.Orientation(..)+       , VL.MarkInterpolation(..)+       , VL.Symbol(..)+       , VL.PointMarker(..)+       , VL.LineMarker(..)+       , VL.MarkErrorExtent(..)+       , VL.TooltipContent(..)+       , VL.ColorGradient(..)+       , VL.GradientProperty(..)+       , VL.TextDirection(..)++         -- ** Cursors+         --+         -- $cursors++       , VL.Cursor(..)++         -- * Creating the Encoding Specification+         --+         -- $encoding++       , VL.encoding+       , VL.Measurement(..)++         -- ** Position Channels+         --+         -- $position++       , VL.position+       , VL.Position(..)++         -- *** Position channel properties++       , VL.PositionChannel(..)++         -- ** Sorting properties+         --+         -- $sortprops++       , VL.SortProperty(..)+       , VL.SortField(..)++         -- ** Axis properties+         --+         -- $axisprops++       , VL.AxisProperty(..)+       , VL.ConditionalAxisProperty(..)++         -- ** Positioning Constants+         --+         -- *** Alignment++       , VL.HAlign(..)+       , VL.VAlign(..)+       , VL.BandAlign(..)++         -- *** Overlapping text++       , VL.OverlapStrategy(..)++         -- *** Legends++       , VL.Side(..)++         -- ** Mark channels+         --+         -- $markprops++       , VL.size+       , VL.color+       , VL.fill+       , VL.stroke+       , VL.strokeWidth+       , VL.opacity+       , VL.fillOpacity+       , VL.strokeOpacity+       , VL.shape++         -- *** Mark Channel properties++       , VL.MarkChannel(..)++         -- *** Mark Legends+         --+         -- $marklegends++       , VL.LegendType(..)+       , VL.LegendProperty(..)+       , VL.LegendOrientation(..)+       , VL.LegendValues(..)++         -- ** Text Channels+         --+         -- $textchannels++       , VL.text+       , VL.tooltip+       , VL.tooltips+       , VL.TextChannel(..)+       , VL.FontWeight(..)++         -- ** Hyperlink Channels+         --+         -- $hyperlink++       , VL.hyperlink+       , VL.HyperlinkChannel(..)++         -- ** URL Channel+         --+         -- $urlchannel++       , VL.url++         -- ** Order Channel+         --+         -- $order++       , VL.order+       , VL.OrderChannel(..)++         -- ** Facet Channel+         --+         -- $facet++       , VL.row+       , VL.column++         -- ** Level of detail Channel+         --+         -- $detail++       , VL.detail+       , VL.DetailChannel(..)++         -- ** Scaling+         --+         -- $scaling++       , VL.ScaleProperty(..)+       , VL.Scale(..)+       , VL.categoricalDomainMap+       , VL.domainRangeMap+       , VL.ScaleDomain(..)+       , VL.ScaleRange(..)+       , VL.ScaleNice(..)++         -- *** Color scaling+         --+         -- $color++       , VL.CInterpolate(..)++         -- * Creating view compositions+         --+         -- $view++       , VL.layer+       , VL.vlConcat+       , VL.columns+       , VL.hConcat+       , VL.vConcat+       , VL.align+       , VL.alignRC+       , VL.spacing+       , VL.spacingRC+       , VL.center+       , VL.centerRC+       , VL.bounds+       , VL.Bounds(..)+       , VL.CompositionAlignment(..)++         -- ** Resolution+         --+         -- $resolution++       , VL.resolve+       , VL.resolution+       , VL.Resolve(..)+       , VL.Channel(..)+       , VL.Resolution(..)++         -- ** Faceted views+         --+         -- $facetview++       , VL.repeat+       , VL.repeatFlow+       , VL.RepeatFields(..)+       , VL.facet+       , VL.facetFlow+       , VL.FacetMapping(..)+       , VL.FacetChannel(..)+       , VL.asSpec+       , VL.specification+       , VL.Arrangement(..)++         -- *** Facet Headers+         --+         -- $facetheaders++       , VL.HeaderProperty(..)++         -- * Creating Selections for Interaction+         --+         -- $selections++       , VL.selection+       , VL.select+       , VL.Selection(..)+       , VL.SelectionProperty(..)+       , VL.Binding(..)+       , VL.BindLegendProperty(..)+       , VL.InputProperty(..)+       , VL.SelectionMarkProperty(..)++       -- ** Selection Resolution+       --+       -- $selectionresolution++       , VL.SelectionResolution(..)++         -- ** Making conditional channel encodings+         --+         -- $conditional++       , VL.BooleanOp(..)++         -- * Top-level Settings+         --+         -- $toplevel++       , VL.name+       , VL.description+       , VL.height+       , VL.heightOfContainer+       , VL.heightStep+       , VL.width+       , VL.widthOfContainer+       , VL.widthStep+       , VL.padding+       , VL.autosize+       , VL.background+       , VL.usermetadata+       , VL.Padding(..)+       , VL.Autosize(..)++         -- *** Title+         --+         -- $title++       , VL.title++         -- *** View Backgroud+         --+         -- $viewbackground++       , VL.viewBackground+       , VL.ViewBackground(..)++         -- ** Style Setting+         --+         -- $configure++       , VL.configure+       , VL.configuration+       , VL.ConfigurationProperty(..)++         -- ** Axis Configuration Options+         --+         -- $axisconfig++       , VL.AxisConfig(..)++         -- ** Legend Configuration Options+         --++       , VL.LegendConfig(..)+       , VL.LegendLayout(..)+       , VL.BaseLegendLayout(..)++         -- ** Scale Configuration Options+         --+         -- $scaleconfig++       , VL.ScaleConfig(..)++         -- ** Scale Range Configuration Options+         --+         -- $scalerangeconfig++       , VL.RangeConfig(..)++         -- ** Title Configuration Options+         --+         -- $titleconfig++       , VL.TitleConfig(..)+       , VL.TitleFrame(..)++         -- ** View Configuration Options+         --+         -- $viewconfig++       , VL.ViewConfig(..)+       , VL.APosition(..)+       , VL.FieldTitleProperty(..)++         -- ** Facet Configuration Options+         --+         -- $facetconfig++       , VL.FacetConfig(..)++         -- ** Concatenated View Configuration Options+         --+         -- $concatconfig++       , VL.ConcatConfig(..)++         -- * General Data types+         --+         -- $generaldatatypes++       , VL.DataValue(..)+       , VL.DataValues(..)++         -- ** Temporal data+         --+         -- $temporaldata++       , VL.DateTime(..)+       , VL.MonthName(..)+       , VL.DayName(..)+       , VL.TimeUnit(..)++         -- * Update notes+         --+         -- $update++         -- ** Version 0.5+         --+         -- $update0500++         -- ** Version 0.4+         --+         -- $update0400++        )+    where++-- VegaLite redefined several prelude functions, such as filter and+-- repeat, so hide the prelude so the documentation links work.+--+import Prelude ()++-- There has been some attempt to separate out the types based+-- on functionality, but it is somewhat hap-hazard. Most of+-- the fuctionality is in the Core and Foundation modules+-- (ie they are the ones that could perhaps be further split up).+--+import qualified Graphics.Vega.VegaLite.Configuration as VL+import qualified Graphics.Vega.VegaLite.Core as VL+import qualified Graphics.Vega.VegaLite.Data as VL+import qualified Graphics.Vega.VegaLite.Foundation as VL+import qualified Graphics.Vega.VegaLite.Geometry as VL+import qualified Graphics.Vega.VegaLite.Input as VL+import qualified Graphics.Vega.VegaLite.Legend as VL+import qualified Graphics.Vega.VegaLite.Mark as VL+import qualified Graphics.Vega.VegaLite.Output as VL+import qualified Graphics.Vega.VegaLite.Scale as VL+import qualified Graphics.Vega.VegaLite.Selection as VL+import qualified Graphics.Vega.VegaLite.Specification as VL+import qualified Graphics.Vega.VegaLite.Time as VL+import qualified Graphics.Vega.VegaLite.Transform as VL+++-- Documentation++-- $dataspec+-- Functions and types for declaring the input data to the+-- visualization. See the+-- [Vega-Lite documentation](https://vega.github.io/vega-lite/docs/data.html#format).++-- $datagen+-- Functions that create new data sources.++-- $dataformat+-- See the Vega-Lite+-- [format](https://vega.github.io/vega-lite/docs/data.html#format) and+-- [JSON](https://vega.github.io/vega-lite/docs/data.html#json) documentation.++-- $transform+-- Functions and types for declaring the transformation rules that+-- are applied to data fields or geospatial coordinates before they+-- are encoded visually.+--+-- In version @0.5.0.0@ the 'VL.TransformSpec' type was introduced to+-- make it clear what functions can be used with 'VL.transform'.++-- $projections+-- See the+-- [Vega-Lite map projection documentation](https://vega.github.io/vega-lite/docs/projection.html).++-- $aggregation+-- See the+-- [Vega-Lite aggregate documentation](https://vega.github.io/vega-lite/docs/aggregate.html).++-- $binning+-- See the+-- [Vega-Lite binning documentation](https://vega.github.io/vega-lite/docs/bin.html).++-- $stacking+-- See the [Vega-Lite stack documentation](https://vega.github.io/vega-lite/docs/stack.html).++-- $calculate+-- See the+-- [Vega-Lite calculate documentation](https://vega.github.io/vega-lite/docs/calculate.html).++-- $filtering+-- See the+-- [Vega-Lite filter documentation](https://vega.github.io/vega-lite/docs/filter.html).++-- $flattening+-- See the Vega-Lite [flatten](https://vega.github.io/vega-lite/docs/flatten.html)+-- documentation.++-- $foldpivot+-- Data tidying operations that reshape the rows and columns of a dataset.+-- See the Vega-Lite [fold](https://vega.github.io/vega-lite/docs/fold.html) and+-- [pivot](https://vega.github.io/vega-lite/docs/pivot.html) documentation.++-- $joining+-- Create lookups between data tables in order to join values from+-- multiple sources. See the+-- [Vega-Lite lookup documentation](https://vega.github.io/vega-lite/docs/lookup.html).++-- $imputation+-- Impute missing data. See the+-- [Vega-Lite impute documentation](https://vega.github.io/vega-lite/docs/impute.html#transform).++-- $sampling+-- See the [Vega-Lite sample documentation](https://vega.github.io/vega-lite/docs/sample.html).++-- $density+-- See the [Vega-Lite density documentation](https://vega.github.io/vega-lite/docs/density.html).++-- $loess+-- See the [Vega-Lite loess documentation](https://vega.github.io/vega-lite/docs/loess.html).++-- $regression+-- See the [Vega-Lite regression documentation](https://vega.github.io/vega-lite/docs/regression.html).++-- $quantile+-- See the [Vega-Lite quantile documentation](https://vega.github.io/vega-lite/docs/quantile.html).++-- $window+-- See the Vega-Lite+-- [window transform field](https://vega.github.io/vega-lite/docs/window.html#field-def)+-- and+-- [window transform](https://vega.github.io/vega-lite/docs/window.html#window-transform-definition)+-- documentation.++-- $markspec+-- Types and functions for declaring the type of visual+-- marks used in the visualization.++-- $markproperties+-- See the Vega-Lite+-- [general mark](https://vega.github.io/vega-lite/docs/mark.html#general-mark-properties),+-- [area mark](https://vega.github.io/vega-lite/docs/area.html#properties),+-- [bar mark](https://vega.github.io/vega-lite/docs/bar.html#properties),+-- [boxplot](https://vega.github.io/vega-lite/docs/boxplot.html#properties),+-- [circle mark](https://vega.github.io/vega-lite/docs/circle.html#properties),+-- [error band](https://vega.github.io/vega-lite/docs/errorband.html#properties),+-- [error bar](https://vega.github.io/vega-lite/docs/errorbar.html#properties),+-- [hyperlink mark](https://vega.github.io/vega-lite/docs/mark.html#hyperlink),+-- [line mark](https://vega.github.io/vega-lite/docs/line.html#properties),+-- [point mark](https://vega.github.io/vega-lite/docs/point.html#properties),+-- [square mark](https://vega.github.io/vega-lite/docs/square.html#properties),+-- [text mark](https://vega.github.io/vega-lite/docs/text.html#properties) and+-- [tick mark](https://vega.github.io/vega-lite/docs/tick.html#properties)+-- property documentation.++-- $cursors+-- See the+-- [CSS cursor documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#Keyword%20values)++-- $encoding+-- Types and functions for declaring which data fields are mapped to which+-- channels. Channels can include: position on screen (e.g. 'VL.X', 'VL.Y'); visual+-- mark properties ('VL.color', 'VL.size', 'VL.stroke', 'VL.shape'); 'VL.text'; 'VL.hyperlink';+-- ordering ('VL.order'); level of 'VL.detail'; and facets for composed+-- visualizations ('VL.facet'). All can be further customised via a series of+-- properties that determine how the encoding is implemented (such as+-- scaling, sorting, and spacing).+--+-- In version @0.5.0.0@ the 'VL.EncodingSpec' type was introduced to+-- make it clear what functions can be used with 'VL.encoding'.++-- $position+-- Control where items appear in the visualization. See the+-- [Vega-Lite position documentation](https://vega.github.io/vega-lite/docs/encoding.html#position).++-- $sortprops+-- See the+-- [Vega-Lite sort documentation](https://vega.github.io/vega-lite/docs/sort.html).++-- $axisprops+-- See the+-- Vega-Lite axis property documentation](https://vega.github.io/vega-lite/docs/axis.html#axis-properties).++-- $markprops+-- Control the appearance of the visual marks in the visualization+-- (e.g. 'VL.color' and 'VL.size').++-- $marklegends+-- See the+-- [Vega-Lite legend property documentation](https://vega.github.io/vega-lite/docs/legend.html#legend-properties).++-- $textchannels+-- Control the appearance of the text and tooltip elements in the visualization.++-- $hyperlink+-- Channels which offer a clickable URL destination. Unlike most other+-- channels, the hyperlink channel has no direct visual expression other than the+-- option of changing the cursor style when hovering, so an encoding will usually+-- pair hyperlinks with other visual channels such as marks or texts.++-- $urlchannel+-- Data-driven URL used for 'VL.Image' specification: a data field can contain+-- URL strings defining the location of image files, or the URL can be+-- given directly.++-- $order+-- Channels that relate to the order of data fields such as for sorting stacking order+-- or order of data points in a connected scatterplot. See the+-- <https://vega.github.io/vega-lite/docs/encoding.html#order Vega-Lite documentation>+-- for further details.++-- $facet+-- Channels for faceting single plots into small multiples. Can be used to create+-- trellis plots or other arrangements in rows and columns. See the+-- <https://vega.github.io/vega-lite/docs/encoding.html#facet Vega-Lite documentation>+-- for further details. See also, <#facetview faceted views> for a more flexible (but+-- more verbose) way of defining faceted views.++-- $detail+-- Used for grouping data but without changing the visual appearance of a mark. When,+-- for example, a field is encoded by color, all data items with the same value for+-- that field are given the same color. When a detail channel encodes a field, all+-- data items with the same value are placed in the same group. This allows, for example+-- a line chart with multiple lines to be created – one for each group. See the+-- <https://vega.github.io/vega-lite/docs/encoding.html#detail Vega-Lite documentation>+-- for more information.++-- NOTE: at present we don't support keyChannel, but leave in in case we+--       ever do.+--+-- ** Dynamic data+--+-- $dyndata+-- Dynamic data (adding or changing values in an existing visualization)+-- is possible with Vega Lite via the+-- <https://vega.github.io/vega/docs/api/view/#data-and-scales Vega View data streaming API>.+-- There is no direct support for this in @hvega@,+-- which only handles setting up the original visualization, but+-- the 'VL.keyChannel' enconding may be useful.++-- $scaling+-- Used to specify how the encoding of a data field should be applied. See the+-- [Vega-Lite scale documentation](https://vega.github.io/vega-lite/docs/scale.html).++-- $color+-- For color interpolation types, see the+-- [Vega-Lite continuous scale documentation](https://vega.github.io/vega-lite/docs/scale.html#continuous).++-- $view+-- Views can be combined to create more complex multiview displays. This may involve+-- layering views on top of each other (superposition) or laying them out in adjacent+-- spaces (juxtaposition using 'VL.repeat', 'VL.repeatFlow', 'VL.facet', 'VL.facetFlow',+-- 'VL.vlConcat', 'VL.hConcat', or 'VL.vConcat'). Where different views have potentially conflicting+-- channels (for example, two position scales in a layered visualization) the rules for+-- resolving them can be defined with 'VL.resolve'. For details of creating composite views see the+-- <https://vega.github.io/vega-lite/docs/composition.html Vega-Lite documentation>.++-- $resolution+-- Control the independence between composed views.+--+-- See the [Vega-Lite resolve documentation](https://vega.github.io/vega-lite/docs/resolve.html).++-- $facetview+-- #facetview#+-- These are small multiples each of which show subsets of the same dataset. The specification+-- determines which field should be used to determine subsets along with their spatial+-- arrangement (in rows or columns). For details see the+-- <https://vega.github.io/vega-lite/docs/facet.html Vega-Lite documentation>.++-- $facetheaders+-- See the+-- [Vega-Lite header documentation](https://vega.github.io/vega-lite/docs/header.html).++-- $selections+-- Selections are the way in which interactions (such as clicking or dragging) can be+-- responded to in a visualization. They transform interactions into data queries.+-- For details, see the+-- <https://vega.github.io/vega-lite/docs/selection.html Vega-Lite documentation>.++-- $selectionresolution+-- Determines how selections are made across multiple views.+-- See the [Vega-lite resolve selection documentation](https://vega.github.io/vega-lite/docs/selection.html#resolve).++-- $conditional+-- To make channel encoding conditional on the result of some interaction, use+-- 'VL.MSelectionCondition', 'VL.TSelectionCondition', or 'VL.HSelectionCondition'. Similarly+-- 'VL.MDataCondition', 'VL.TDataCondition', or 'VL.HDataCondition' will encode a mark+-- conditionally depending on some data properties such as whether a datum is null+-- or an outlier.+--+-- For interaction, once a selection has been defined and named, supplying a set of+-- encodings allow mark encodings to become dependent on that selection.+-- 'VL.MSelectionCondition' is followed firstly a (Boolean) selection and then an+-- encoding if that selection is true and another encoding to be applied if it is false.+-- The color specification below states \"whenever data marks are selected with an+-- interval mouse drag, encode the cylinder field with an ordinal color scheme,+-- otherwise make them grey\":+--+-- @+-- sel = 'VL.selection' . 'VL.select' "myBrush" 'VL.Interval' []+--+-- enc = 'VL.encoding'+--         . 'VL.position' 'VL.X' [ 'VL.PName' \"Horsepower\", 'VL.PmType' 'VL.Quantitative' ]+--         . 'VL.position' 'VL.Y' [ 'VL.PName' \"Miles_per_Gallon\", 'VL.PmType' Quantitative ]+--         . 'VL.color'+--             [ 'VL.MSelectionCondition' ('VL.SelectionName' "myBrush")+--                 [ 'VL.MName' \"Cylinders\", 'VL.MmType' 'VL.Ordinal' ]+--                 [ 'VL.MString' "grey" ]+--             ]+-- @+--+-- In a similar way, 'VL.MDataCondition' will encode a mark depending on whether any+-- predicate tests are satisfied. Unlike selections, multiple conditions and associated+-- encodings can be specified. Each test condition is evaluated in order and only on+-- failure of the test does encoding proceed to the next test. If no tests are true,+-- the encoding in the final parameter is applied in a similar way to @case of@+-- expressions:+--+-- @+-- enc = 'VL.encoding'+--         . 'VL.position' 'VL.X' [ 'VL.PName' \"value\", 'VL.PmType' 'VL.Quantitative' ]+--           . 'VL.color'+--               [ 'VL.MDataCondition'+--                    [ ( 'VL.Expr' "datum.value < 40", [ 'VL.MString' "blue" ] )+--                    , ( 'VL.Expr' "datum.value < 50", [ 'VL.MString' "red" ] )+--                    , ( 'VL.Expr' "datum.value < 60", [ 'VL.MString' "yellow" ] )+--                    ]+--                    [ 'VL.MString' "black" ]+--               ]+-- @+--+-- For more details, see the+-- <https://vega.github.io/vega-lite/docs/condition.html Vega-Lite documentation>.++-- $toplevel+-- These are in addition to the data and transform options described above,+-- and are described in the+-- [Vega-Lite top-level spec documentation](https://vega.github.io/vega-lite/docs/spec.html#top-level-specifications).++-- $title+-- Per-title settings. Use 'VL.TitleStyle' to change the appearance of all+-- titles in a multi-view specification.++-- $viewbackground+-- The background of a single view in a view composition can be styled independently+-- of other views. For more details see the+-- [Vega-Lite view background documentation](https://vega.github.io/vega-lite/docs/spec.html#view-background).++-- $configure+-- In version @0.5.0.0@ the 'VL.ConfigureSpec' type was introduced to+-- make it clear that only 'VL.configuration' should be used with+-- 'VL.configure'.++-- $axisconfig+-- See the+-- [Vega-Lite axis config documentation](https://vega.github.io/vega-lite/docs/axis.html#general-config).++-- $scaleconfig+-- See the+-- [Vega-Lite scale configuration documentation](https://vega.github.io/vega-lite/docs/scale.html#scale-config).++-- $scalerangeconfig+-- See the+-- [Vega-Lite scheme configuration documentation](https://vega.github.io/vega/docs/schemes/#scheme-properties).++-- $titleconfig+-- Unlike 'VL.title', these options apply to __all__ titles if multiple views+-- are created. See the+-- [Vega-Lite title configuration documentation](https://vega.github.io/vega-lite/docs/title.html#config).++-- $viewconfig+-- See the+-- [Vega-Lite view configuration documentation](https://vega.github.io/vega-lite/docs/spec.html#config).++-- $facetconfig+-- See the+-- [Vega-Lite facet configuration documentation](https://vega.github.io/vega-lite/docs/facet.html#facet-configuration).++-- $concatconfig+-- See the+-- [Vega-Lite concat configuration documentation](https://vega.github.io/vega-lite/docs/concat.html#concat-configuration).++-- $generaldatatypes+-- In addition to more general data types like integers and string, the following types+-- can carry data used in specifications.++-- $temporaldata+-- See the+-- [Vega-Lite dateTime documentation](https://vega.github.io/vega-lite/docs/types.html#datetime)+-- and the [Vega-Lite time unit documentation](https://vega.github.io/vega-lite/docs/timeunit.html).++-- $update+-- The following section describes how to update code that used+-- an older version of @hvega@.++-- $update0500+-- The @0.5.0.0@ release now creates specifications using version 4+-- of the Vega-Lite schema (version 0.4 of @hvega@ used version 3).+-- The 'VL.toVegaLiteSchema' function can be used along with the+-- 'VL.vlSchema3' to use version 3 for the output.+--+-- There is more-extensive use of type aliases, such as 'VL.Color',+-- and the introduction of several more (e.g. 'VL.DashStyle' and+-- 'VL.FieldName'). These do not add any type safety, but help the+-- documentation (as they provide a single place to explain the meaning+-- and any constraints on a particular value). There are some+-- changes that do improve type safety, discussed in the+-- \"Breaking changes\" section below.+--+-- Documentation improvements, including a new section in the+-- tutorial on choropleths contributed by Adam Conner-Sax, and+-- plots using an Aitoff projection contributed by Jo Wood.+--+-- __Changes in Vega-Lite 4__:+--+-- * The background of a visualization is now white by default whereas in+--   previous versions it was transparent. If you+--   need a transparent background then add the following configuration+--   to the visualization:+--   @'VL.configuration' ('VL.Background' \"rgba(0,0,0,0)\")@.+--+-- * Tooltips are now disabled by default. To enable, either use the+--   'VL.tooltip' channel or by setting @'VL.MTooltip' 'VL.TTEncoding'@.+--+-- * Title (and subtitle) strings can now be split across multiple lines:+--   use @'\n'@ to indicate where line breaks should occur.+--+-- Note that the behavior of a Vega-Lite visualization seems to depend+-- on both the version of the schema it is using, and the version of the+-- visualization software used to display it (e.g.+-- <https://vega.github.io/vega-lite/usage/embed.html Vega-Embed>).+--+-- __New functionality__:+--+-- This does not include new configuration options listed in the+-- \"new constructors\" section below.+--+-- * Colors are now cleaned of extraneous whitespace and, if empty,+--   converted to the JSON null value. This should not change the behavior+--   of any existing visualization.+--+-- * The 'VL.pivot' transform has been added, along with the 'VL.PivotProperty'+--   preferences type. This is the inverse of 'VL.fold'.+--+-- * The 'VL.density' transform has been added, along with the 'VL.DensityProperty'+--   type, to support kernel density estimation (such as generating a+--   continuous distribution from a discrete one).+--+-- * The 'VL.loess' transform has been added, along with the 'VL.LoessProperty'+--   type, to support estimating a trend (scatterplot smoothing).+--+-- * The 'VL.regression' transform has been added, along with the 'VL.RegressionProperty'+--   and 'VL.RegressionMethod' types, to support regression analysis.+--+-- * The 'VL.quantile' transform has been added, along with the+--   'VL.QuantileProperty' type, to support quantile analysis.+--+-- * The 'VL.url' encoding has been added for displaying images (via the+--   new 'VL.Image' mark type.+--+-- * The 'VL.lookupSelection' transform has been added to support+--   joining data via a selection. The 'VL.SelectionLabel' type alias+--   has been added as a guide for the documentation.+--+-- * The 'VL.heightOfContainer' and 'VL.widthOfContainer' functions+--   have been added to support responsive sizing, although I have not+--   had much success in getting them to work!+--+-- * The 'VL.tooltip' encoding will now turn off tooltips if given an+--   empty list (although note that tooltips are now off by default in+--   Vega-Lite 4).+--+-- __Breaking changes__:+--+-- * The @combineSpecs@ function has been removed.+--+-- * In an attempt to provide some type safety, the 'VL.encoding',+--   'VL.transform', 'VL.resolve', 'VL.selection', and 'VL.configure'+--   functions now take specialised types - 'VL.EncodingSpec',+--   'VL.TransformSpec', 'VL.ResolveSpec', 'VL.SelectSpec', and+--   'VL.ConfigureSpec' respectively - rather than the generic+--   'VL.LabelledSpec' type. Simple visualizations should remain+--   unchanged, but helper functions may need to have their type signatures+--   updated.+--+-- * The 'VL.lookup' function now takes the new 'VL.LookupFields'+--   type rather than a list of field names. The 'VL.lookupAs' function+--   is deprecated, as its functionality is now possible with+--   'VL.lookup'.+--+-- * The @RemoveInvalid@ constructor has been removed from+--   'VL.ConfigurationProperty'. To indicate how missing values should+--   be handled use the new 'VL.MRemoveInvalid' constructor from+--   'VL.MarkProperty' instead. This means changing+--   @'VL.configuration' (RemoveInvalid b)@ to+--   @'VL.configuration' ('VL.MarkStyle' ['VL.MRemoveInvalid' b])@.+--+-- * The @Stack@ constructor has been removed from+--   'VL.ConfigurationProperty'.+--+-- * The @SRangeStep@ constructor from 'VL.ScaleProperty' has been+--   removed. The 'VL.widthStep' and 'VL.heightStep' functions should+--   be used instead.+--+-- * The @ViewWidth@ and @ViewHeight@ constructors from 'VL.ViewConfig'+--   have been replaced by 'VL.ViewContinuousWidth', 'VL.ViewContinuousHeight',+--   'VL.ViewDiscreteWidth', and 'VL.ViewDiscreteHeight' constructors+--   (actually, they remain but are now deprecated and the+--   continuous-named versions should be used instead).+--+-- * The @SCRangeStep@ and @SCTextXRangeStep@ constructors of+--   'VL.ScaleConfig' have been removed. The new 'VL.ViewStep' constructor+--   of 'VL.ViewConfig' should be used instead. That is, users should+--   change @'VL.configuration' ('VL.Scale' [SCRangeStep (Just x)])@+--   to @'VL.configuration' ('VL.View' ['VL.ViewStep' x])@.+--+-- * The @ShortTimeLabels@, @LeShortTimeLabels@, and @MShortTImeLabels@+--   constructors have been removed from `VL.AxisConfig`, `VL.LegendConfig`,+--   and `VL.MarkProperty` respectively.+--+-- __New constructors__:+--+-- Note that some new constructors have been described in the \"breaking+-- changes\" section above and so are not repeated here.+--+-- * 'VL.AxisProperty' has gained the 'VL.AxDataCondition' constructor for+--   marking a subset of axis properties as being conditional on their+--   position, and the 'VL.ConditionalAxisProperty' for defining which+--   properties (grid, label, and tick) can be used in this way.+--   It has also gained the 'VL.AxLabelExpr' constructor, which allows you+--   to change the content of axis labels, 'VL.AxTickBand' for positioning+--   the labels for band scales (and the associated 'VL.BandAlign' type),+--   'VL.AxTitleLineHeight' to specify the line height, and+--   'VL.AxTranslateOffset' for applying a translation offset to the+--   axis group mark.+--+-- * 'VL.AxisConfig' has gained 'VL.TickBand', 'VL.TitleLineHeight', and+--   'VL.TranslateOffset', matching the additions to 'VL.AxisProperty'.+--+-- * The 'VL.ViewBackgroundStyle' constructor has been added to 'VL.ViewConfig'.+--+-- * The 'VL.TitleConfig' type gained the following constructors:+--   'VL.TAlign', 'VL.TdX', 'VL.TdY', 'VL.TLineHeight',+--   'VL.TSubtitle', 'VL.TSubtitleColor', 'VL.TSubtitleFont',+--   'VL.TSubtitleFontSize', 'VL.TSubtitleFontStyle',+--   'VL.TSubtitleFontWeight', 'VL.TSubtitleLineHeight',+--   and 'VL.TSubtitlePadding'.+--+-- * The 'VL.AFitX' and 'VL.AFitY' constructors have been added to the+--   @Autosize@ type.+--+-- * The 'VL.SelectionProperty' type has gained the 'VL.BindLegend'+--   constructor - and associated 'VL.BindLegendProperty' type - to+--   allow selection of legend items (for categorical data only).+--+-- * The 'VL.TextChannel' type has gained 'VL.TString', which lets you specify+--   the text content as a literal.+--+-- * Two new projections - 'VL.EqualEarth' and 'VL.NaturalEarth1' - have been+--   added to the 'VL.Projection' type.+--+-- * Support for color gradients has been added for marks via the+--   'VL.MColorGradient', 'VL.MFillGradient', and+--   'VL.MStrokeGradient' constructors of+--   'VL.MarkProperty', along with the new 'VL.ColorGradient' and+--   'VL.GradientProperty' types for defining the appearance of the+--   gradient. The 'VL.GradientCoord' and 'VL.GradientStops' type aliases+--   have also been added (although they provides no type safety).+--+-- * The 'VL.Image' constructor has been added to 'VL.Mark', for use+--   with the new 'VL.url' encoding, and 'VL.MAspect' to 'VL.MarkProperty'.+--+-- * The 'VL.MCornerRadius' constructor has been added to 'VL.MarkProperty'+--   to set the corner radius of rectangular marks. If that's not enough,+--   you can change individual corners with one of:+--   'VL.MCornerRadiusTL', 'VL.MCornerRadiusTR', 'VL.MCornerRadiusBL',+--   and 'VL.MCornerRadiusBR'.+--+-- * The 'VL.MDir', 'VL.MEllipsis', and 'VL.MLimit' constructors have+--   been added to 'VL.MarkProperty' to control how text is+--   truncated. The 'VL.TextDirection' type has been added for use+--   with 'VL.MDir'.+--+-- * The 'VL.MarkProperty' type has gained 'VL.MLineBreak' and+--   'VL.MLineHeight' constructors for controlling how multi-line+--   labels are displayed. Note that @hvega@ will __always__ split on+--   the newline character (@\\n@), which will over-ride the+--   'VL.MLineBreak' setting.+--+-- * The 'VL.DTMonthNum' and 'VL.DTDayNum' constructors have been added+--   to @DateTime@.+--+-- * The 'VL.BinProperty' type has gained the 'VL.SelectionExtent'+--   constructor, which defines the bin range as an interval selection.+--+-- * The 'VL.PositionChannel' type has gained 'VL.PBand', for defining+--   the size of a mark relative to a band, and 'VL.MarkProperty' has+--   added 'VL.MTimeUnitBand' and 'VL.MTimeUnitBandPosition'.+--+-- __Bug Fixes__ in this release:+--+-- * The selection property @'VL.SInitInterval' Nothing Nothing@ is+--   now a no-op (as it does nothing), rather than generating invalid JSON.+--+-- * The following options or symbols generated incorrect JSON output:+--   'VL.ONone', 'VL.LSymbolStrokeWidth', 'VL.LeLabelOpacity'.+--++-- $update0400+-- The @0.4.0.0@ release added a large number of functions, types, and+-- constructors, including:+--+-- 'VL.toVegaLiteSchema' has been added to allow you to specify a+-- different Vega-Lite schema. 'VL.toVegaLite' uses version 3 but+-- version 4 is being worked on as I type this. The 'VL.vlSchema'+-- function has been added, along with 'VL.vlSchema4', 'VL.vlSchema3',+-- and 'VL.vlSchema2' values. The 'VL.toHtmlWith' and 'VL.toHtmlFileWith'+-- functions have been added to support more control over the+-- embedding of the Vega-Lite visualizations, and the versions of+-- the required Javascript libraries used by the @toHtmlXXX@ routines+-- has been updated.+--+-- The 'VL.VLProperty' type now exports its constructors, to support users+-- who may need to tweak or augment the JSON Vega-Lite specification+-- created by @hvega@: see [issue+-- 17](https://github.com/DougBurke/hvega/issues/17). It has also gained+-- several new constructors and associated functions, which are given in+-- brackets after the constructor: 'VL.VLAlign' ('VL.align'); 'VL.VLBounds'+-- ('VL.bounds'); 'VL.VLCenter' ('VL.center', 'VL.centerRC'); 'VL.VLColumns'+-- ('VL.columns'); 'VL.VLConcat' ('VL.vlConcat'); 'VL.VLSpacing' ('VL.alignRC',+-- 'VL.spacing', 'VL.spacingRC'); 'VL.VLUserMetadata' ('VL.usermetadata'); and+-- 'VL.VLViewBackground' ('VL.viewBackground'). It is expected that you will be+-- using the functions rather the constructors!+--+-- Four new type aliases have been added: 'VL.Angle', 'VL.Color', 'VL.Opacity',+-- and 'VL.ZIndex'. These do not provide any new functionality but do+-- document intent.+--+-- The 'VL.noData' function has been added to let compositions define the+-- source of the data (whether it is from the parent or not), and data+-- sources can be named with 'VL.dataName'. Data can be created with+-- 'VL.dataSequence', 'VL.dataSequenceAs', and 'VL.sphere'. Graticules can be+-- created with 'VL.graticule'.  The 'VL.NullValue' type has been added to+-- 'VL.DataValue' to support data sources that are missing elements, but for+-- more-complex cases it is suggested that you create your data as an+-- Aeson Value and then use 'VL.dataFromJson'. Support for data imputation+-- (creating new values based on existing data) has been added, as+-- discussed below.+--+-- The alignment, size, and composition of plots can be defined and+-- changed with 'VL.align', 'VL.alignRC', 'VL.bounds', 'VL.center', 'VL.centerRC',+-- 'VL.columns', 'VL.spacing', and 'VL.spacingRC'.+--+-- Plots can be combined and arranged with: 'VL.facet', 'VL.facetFlow',+-- 'VL.repeat', 'VL.repeatFlow', and 'VL.vlConcat'+--+-- New functions for use in a 'VL.transform': 'VL.flatten', 'VL.flattenAs',+-- 'VL.fold', 'VL.foldAs', 'VL.impute', and 'VL.stack'.+--+-- New functions for use with 'VL.encoding': 'VL.fillOpacity', 'VL.strokeOpacity',+-- 'VL.strokeWidth',+--+-- The ability to arrange specifications has added the "flow" option+-- (aka "repeat"). This is seen in the addition of the 'VL.Flow' constructor+-- to the 'VL.Arrangement' type - which is used with 'VL.ByRepeatOp',+-- 'VL.HRepeat', 'VL.MRepeat', 'VL.ORepeat', 'VL.PRepeat', and 'VL.TRepeat'.+--+-- The 'VL.Mark' type has gained 'VL.Boxplot', 'VL.ErrorBar', 'VL.ErrorBand', and+-- 'VL.Trail' constructors. The 'VL.MarkProperty' type has gained 'VL.MBorders',+-- 'VL.MBox', 'VL.MExtent', 'VL.MHeight', 'VL.MHRef', 'VL.MLine', 'VL.MMedian', 'VL.MOrder',+-- 'VL.MOutliers', 'VL.MNoOutliers', 'VL.MPoint', 'VL.MRule', 'VL.MStrokeCap', 'VL.MStrokeJoin',+-- 'VL.MStrokeMiterLimit', 'VL.MTicks', 'VL.MTooltip', 'VL.MWidth', 'VL.MX', 'VL.MX2',+-- 'VL.MXOffset', 'VL.MX2Offset', 'VL.MY', 'VL.MY2', 'VL.MYOffset', and 'VL.MY2Offset'+-- constructors.+--+-- The 'VL.Position' type has added 'VL.XError', 'VL.XError2', 'VL.YError', and+-- 'VL.YError2' constructors.+--+-- The 'VL.MarkErrorExtent' type was added.+--+-- The 'VL.BooleanOp' type has gained the 'VL.FilterOp' and 'VL.FilterOpTrans'+-- constructors which lets you use 'VL.Filter' expressions as part of a+-- boolean operation. The 'VL.Filter' type has also gained expresiveness,+-- with the 'VL.FLessThan', 'VL.FLessThanEq', 'VL.FGreaterThan', 'VL.FGreaterThanEq',+-- and 'VL.FValid'.+--+-- The 'VL.Format' type has gained the 'VL.DSV' constructor, which allow you+-- to specify the separator character for column data.+--+-- The MarkChannel type has been expanded to include: 'VL.MBinned', 'VL.MSort',+-- 'VL.MTitle', and 'VL.MNoTitle'. The PositionChannel type has added+-- 'VL.PHeight', 'VL.PWidth', 'VL.PNumber', 'VL.PBinned', 'VL.PImpute', 'VL.PTitle', and+-- 'VL.PNoTitle' constructors.+--+-- The LineMarker and PointMarker types have been added for use with+-- 'VL.MLine' and 'VL.MPoint' respectively (both from 'VL.MarkProperty').+--+-- The ability to define the binning property with+-- 'VL.binAs', 'VL.DBin', 'VL.FBin', 'VL.HBin', 'VL.MBin', 'VL.OBin', 'VL.PBin', and 'VL.TBin' has+-- been expanded by adding the 'VL.AlreadyBinned' and 'VL.BinAnchor'+-- constructors to 'VL.BinProperty', as well as changing the 'VL.Divide'+-- constructor (as described below).+--+-- The 'VL.StrokeCap' and 'VL.StrokeJoin' types has been added. These are used+-- with 'VL.MStrokeCap', 'VL.VBStrokeCap', and 'VL.ViewStrokeCap' and+-- 'VL.MStrokeJoin', 'VL.VBStrokeJoin', and 'VL.ViewStrokeJoin' respectively.+--+-- The 'VL.StackProperty' constructor has been added with the 'VL.StOffset'+-- and 'VL.StSort' constructors. As discussed below this is a breaking change+-- since the old StackProperty type has been renamed to 'VL.StackOffset'.+--+-- The 'VL.ScaleProperty' type has seen significant enhancement, by adding+-- the constructors: 'VL.SAlign', 'VL.SBase', 'VL.SBins', 'VL.SConstant' and+-- 'VL.SExponent'.  The 'VL.Scale' tye has added 'VL.ScSymLog' 'VL.ScQuantile',+-- 'VL.ScQuantize', and 'VL.ScThreshold'.+--+-- The 'VL.SortProperty' type has new constructors: 'VL.CustomSort',+-- 'VL.ByRepeatOp', 'VL.ByFieldOp', and 'VL.ByChannel'. See the breaking-changes+-- section below for the constructors that were removed.+--+-- The 'VL.AxisProperty' type has seen significant additions, including:+-- 'VL.AxBandPosition', 'VL.AxDomainColor', 'VL.AxDomainDash',+-- 'VL.AxDomainDashOffset', 'VL.AxDomainOpacity', 'VL.AxDomainWidth',+-- 'VL.AxFormatAsNum', 'VL.AxFormatAsTemporal', 'VL.AxGridColor', 'VL.AxGridDash',+-- 'VL.AxGridDashOffset', 'VL.AxGridOpacity', 'VL.AxGridWidth', 'VL.AxLabelAlign',+-- 'VL.AxLabelBaseline', 'VL.AxLabelNoBound', 'VL.AxLabelBound', 'VL.AxLabelBoundValue',+-- 'VL.AxLabelColor', 'VL.AxLabelNoFlush', 'VL.AxLabelFlush', 'VL.AxLabelFlushValue',+-- 'VL.AxLabelFlushOffset', 'VL.AxLabelFont', 'VL.AxLabelFontSize',+-- 'VL.AxLabelFontStyle', 'VL.AxLabelFontWeight', 'VL.AxLabelLimit',+-- 'VL.AxLabelOpacity', 'VL.AxLabelSeparation', 'VL.AxTickColor', 'VL.AxTickDash',+-- 'VL.AxTickDashOffset', 'VL.AxTickExtra', 'VL.AxTickMinStep', 'VL.AxTickOffset',+-- 'VL.AxTickOpacity', 'VL.AxTickRound', 'VL.AxTickWidth', 'VL.AxNoTitle',+-- 'VL.AxTitleAnchor', 'VL.AxTitleBaseline', 'VL.AxTitleColor', 'VL.AxTitleFont',+-- 'VL.AxTitleFontSize', 'VL.AxTitleFontStyle', 'VL.AxTitleFontWeight',+-- 'VL.AxTitleLimit', 'VL.AxTitleOpacity', 'VL.AxTitleX', and 'VL.AxTitleY'.+--+-- The 'VL.AxisConfig' has seen a similar enhancement, and looks similar+-- to the above apart from the constructors do not start with @Ax@.+--+-- The 'VL.LegendConfig' type has been significantly expanded and, as+-- discussed in the Breaking Changes section, changed. It has gained:+-- 'VL.LeClipHeight', 'VL.LeColumnPadding', 'VL.LeColumns', 'VL.LeGradientDirection',+-- 'VL.LeGradientHorizontalMaxLength', 'VL.LeGradientHorizontalMinLength',+-- 'VL.LeGradientLength', 'VL.LeGradientOpacity', 'VL.LeGradientThickness',+-- 'VL.LeGradientVerticalMaxLength', 'VL.LeGradientVerticalMinLength',+-- 'VL.LeGridAlign', 'VL.LeLabelFontStyle', 'VL.LeLabelFontWeight',+-- 'VL.LeLabelOpacity', 'VL.LeLabelOverlap', 'VL.LeLabelPadding',+-- 'VL.LeLabelSeparation', 'VL.LeLayout', 'VL.LeLeX', 'VL.LeLeY', 'VL.LeRowPadding',+-- 'VL.LeSymbolBaseFillColor', 'VL.LeSymbolBaseStrokeColor', 'VL.LeSymbolDash',+-- 'VL.LeSymbolDashOffset', 'VL.LeSymbolDirection', 'VL.LeSymbolFillColor',+-- 'VL.LeSymbolOffset', 'VL.LeSymbolOpacity', 'VL.LeSymbolStrokeColor', 'VL.LeTitle',+-- 'VL.LeNoTitle', 'VL.LeTitleAnchor', 'VL.LeTitleFontStyle', 'VL.LeTitleOpacity',+-- and 'VL.LeTitleOrient'.+--+-- The 'VL.LegendOrientation' type has gained 'VL.LOTop' and 'VL.LOBottom'.+--+-- The 'VL.LegendLayout' and 'VL.BaseLegendLayout' types are new, and used+-- with 'VL.LeLayout' to define the legent orient group.+--+-- The 'VL.LegendProperty' type gained: 'VL.LClipHeight', 'VL.LColumnPadding',+-- 'VL.LColumns', 'VL.LCornerRadius', 'VL.LDirection', 'VL.LFillColor',+-- 'VL.LFormatAsNum', 'VL.LFormatAsTemporal', 'VL.LGradientLength',+-- 'VL.LGradientOpacity', 'VL.LGradientStrokeColor', 'VL.LGradientStrokeWidth',+-- 'VL.LGradientThickness', 'VL.LGridAlign', 'VL.LLabelAlign', 'VL.LLabelBaseline',+-- 'VL.LLabelColor', 'VL.LLabelFont', 'VL.LLabelFontSize', 'VL.LLabelFontStyle',+-- 'VL.LLabelFontWeight', 'VL.LLabelLimit', 'VL.LLabelOffset', 'VL.LLabelOpacity',+-- 'VL.LLabelOverlap', 'VL.LLabelPadding', 'VL.LLabelSeparation', 'VL.LRowPadding',+-- 'VL.LStrokeColor', 'VL.LSymbolDash', 'VL.LSymbolDashOffset',+-- 'VL.LSymbolFillColor', 'VL.LSymbolOffset', 'VL.LSymbolOpacity', 'VL.LSymbolSize',+-- 'VL.LSymbolStrokeColor', 'VL.LSymbolStrokeWidth', 'VL.LSymbolType',+-- 'VL.LTickMinStep', 'VL.LNoTitle', 'VL.LTitleAlign', 'VL.LTitleAnchor',+-- 'VL.LTitleBaseline', 'VL.LTitleColor', 'VL.LTitleFont', 'VL.LTitleFontSize',+-- 'VL.LTitleFontStyle', 'VL.LTitleFontWeight', 'VL.LTitleLimit', 'VL.LTitleOpacity',+-- 'VL.LTitleOrient', 'VL.LTitlePadding', 'VL.LeX', and 'VL.LeY'.+--+-- 'VL.Projection' has gained the 'VL.Identity' constructor. The+-- 'VL.ProjectionProperty' type has gained 'VL.PrScale', 'VL.PrTranslate',+-- 'VL.PrReflectX', and 'VL.PrReflectY'. The 'VL.GraticuleProperty' type was+-- added to configure the appearance of graticules created with+-- 'VL.graticule'.+--+-- The 'VL.CompositionAlignment' type was added and is used with 'VL.align',+-- 'VL.alignRC', 'VL.LeGridAlign', and 'VL.LGridAlign'.+--+-- The 'VL.Bounds' type was added for use with 'VL.bounds'.+--+-- The 'VL.ImputeProperty' and 'VL.ImMethod' types were added for use with+-- 'VL.impute' and 'VL.PImpute'.+--+-- The 'VL.ScaleConfig' type has gained 'VL.SCBarBandPaddingInner',+-- 'VL.SCBarBandPaddingOuter', 'VL.SCRectBandPaddingInner', and+-- 'VL.SCRectBandPaddingOuter'.+--+-- The 'VL.SelectionProperty' type has gained 'VL.Clear', 'VL.SInit', and+-- 'VL.SInitInterval'.+--+-- The Channel type has gained: 'VL.ChLongitude', 'VL.ChLongitude2',+-- 'VL.ChLatitude', 'VL.ChLatitude2', 'VL.ChFill', 'VL.ChFillOpacity', 'VL.ChHref',+-- 'VL.ChKey', 'VL.ChStroke', 'VL.ChStrokeOpacity'.  'VL.ChStrokeWidth', 'VL.ChText',+-- and 'VL.ChTooltip'.+--+-- The 'VL.TitleConfig' type has gained: 'VL.TFontStyle', 'VL.TFrame', 'VL.TStyle',+-- and 'VL.TZIndex'.+--+-- The 'VL.TitleFrame' type is new and used with 'VL.TFrame' from 'VL.TitleConfig'.+--+-- The 'VL.ViewBackground' type is new and used with 'VL.viewBackground'.+--+-- The 'VL.ViewConfig' type has gained 'VL.ViewCornerRadius', 'VL.ViewOpacity',+-- 'VL.ViewStrokeCap', 'VL.ViewStrokeJoin', and 'VL.ViewStrokeMiterLimit'.+--+-- The 'VL.ConfigurationProperty' type, used with 'VL.configuration', has+-- gained 'VL.ConcatStyle', 'VL.FacetStyle', 'VL.GeoshapeStyle', 'VL.HeaderStyle',+-- 'VL.NamedStyles', and 'VL.TrailStyle' constructors.+--+-- The 'VL.ConcatConfig' type was added for use with the 'VL.ConcatStyle',+-- and the 'VL.FacetConfig' type for the 'VL.FacetStyle'+-- configuration settings.+--+-- The 'VL.HeaderProperty' type has gained: 'VL.HFormatAsNum',+-- 'VL.HFormatAsTemporal', 'VL.HNoTitle', 'VL.HLabelAlign', 'VL.HLabelAnchor',+-- 'VL.HLabelAngle', 'VL.HLabelColor', 'VL.HLabelFont', 'VL.HLabelFontSize',+-- 'VL.HLabelLimit', 'VL.HLabelOrient', 'VL.HLabelPadding', 'VL.HTitleAlign',+-- 'VL.HTitleAnchor', 'VL.HTitleAngle', 'VL.HTitleBaseline', 'VL.HTitleColor',+-- 'VL.HTitleFont', 'VL.HTitleFontSize', 'VL.HTitleFontWeight', 'VL.HTitleLimit',+-- 'VL.HTitleOrient', and 'VL.HTitlePadding'.+--+-- The 'VL.HyperlinkChannel' type has gained 'VL.HBinned'.+--+-- The 'VL.FacetChannel' type has gained 'VL.FSort', 'VL.FTitle', and 'VL.FNoTitle'.+--+-- The 'VL.TextChannel' type has gained 'VL.TBinned', 'VL.TFormatAsNum',+-- 'VL.TFormatAsTemporal', 'VL.TTitle', and 'VL.TNoTitle'.+--+-- The 'VL.TooltipContent' type was added, for use with 'VL.MTooltip'.+--+-- The 'VL.Symbol' type has gained: 'VL.SymArrow', 'VL.SymStroke',+-- 'VL.SymTriangle', 'VL.SymTriangleLeft', 'VL.SymTriangleRight', and+-- 'VL.SymWedge'.+--+-- There are a number of __breaking changes__ in this release (some+-- of which were mentioned above):+--+-- * The 'VL.title' function now takes a second argument, a list of 'VL.TitleConfig'+--   values for configuring the appearance of the title.+--+-- * The @SReverse@ constructor was removed from 'VL.ScaleProperty' as it+--   represented a Vega, rather than Vega-Lite, property. The @xSort@+--   constructors are used to change the order of an item (e.g.+--   'VL.PSort', 'VL.MSort').+--+-- * The @ScSequential@ constructor was removed from 'VL.Scale' as+--   'VL.ScLinear' should be used.+--+-- * The 'VL.SortProperty' type has had a number of changes: the @Op@,+--   @ByField@, and @ByRepeat@ constructors have been removed, and+--   'VL.ByRepeatOp', 'VL.ByFieldOp', and 'VL.ByChannel' constructors have been+--   added.+--+-- * The @AxTitleMaxLength@ and @TitleMaxLength@ constructors have been+--   removed (from 'VL.AxisProperty' and 'VL.AxisConfig' respectively) as they+--   are invalid. The 'VL.AxTitleLimit' (new in this release) and+--   'VL.TitleLimit' constructors should be used instead.+--+-- * 'VL.AxisProperty': the 'VL.AxValues' constructor has been changed from+--   accepting a list of doubles to 'VL.DataValues'. The 'VL.AxDates'+--   constructor has been deprecated and 'VL.AxValues' should be used+--   instead.+--+-- * There have been significant changes to the 'VL.LegendConfig' type: the+--   @EntryPadding@, @GradientHeight@, @GradientLabelBaseline@,+--   @GradientWidth@, and @SymbolColor@ constructors have been removed;+--   the renaming constructors have been renamed so they all begin with+--   @Le@ (e.g. @Orient@ is now 'VL.LeOrient', and 'VL.Orient' has been added+--   to 'VL.AxisConfig'); and new constructors have been added.+--+-- * The @StackProperty@ type has been renamed to 'VL.StackOffset' and its+--   constructors have changed, and a new 'VL.StackProperty'+--   type has been added (that references the 'VL.StackOffset' type).+--+-- * The @Average@ constructor of 'VL.Operation' was removed, and 'VL.Mean'+--   should be used instead.+--+-- * The @LEntryPadding@ constructor of 'VL.LegendProperty' was removed.+--+-- * The arguments to the 'VL.MDataCondition', 'VL.TDataCondition', and+--   'VL.HDataCondition' constructors - of 'VL.MarkChannel', 'VL.TextChannel',+--   and 'VL.HyperlinkChannel' respectively - have changed to support+--   accepting multiple expressions.+--+-- * The @MarkOrientation@ type has been renamed 'VL.Orientation'.+--+-- * The constructors of the 'VL.ViewConfig' type have been renamed so they+--   all begin with @View@ (to match 'VL.ViewWidth' and 'VL.ViewHeight').+--+-- * The constructors of the 'VL.ProjectionProperty' type have been renamed+--   so that they begin with @Pr@ rather than @P@ (to avoid conflicts+--   with the 'VL.PositionChannel' type).+--+-- * The 'VL.Divide' constructor of 'VL.BinProperty' now takes a list of+--   Doubles rather than two.+--+-- * The 'VL.TitleConfig' type has gained the following constructors:+--   'VL.TFontStyle', 'VL.TFrame', 'VL.TStyle', and 'VL.TZIndex'. The 'VL.TitleFrame'+--   type was added for use with 'VL.TFrame'.+--+-- * The 'VL.ArgMax' and 'VL.ArgMin' constructors of 'VL.Operation' now take an+--   optional field name, to allow them to be used as part of an encoding+--   aggregation (e.g. with 'VL.PAggregate').+--+-- * The \"z index" value has changed from an 'VL.Int' to the 'VL.ZIndex' type.+--+-- * The constructors for the 'VL.Symbol' type now all start with @Sym@, so+--   @Cross@, @Diamond@, @TriangleUp@, @TriangleDown@, and @Path@ have+--   been renamed to 'VL.SymCross', 'VL.SymDiamond', 'VL.SymTriangleUp',+--   'VL.SymTriangleDown', and 'VL.SymPath', respectively.+--+-- * The @Legend@ type has been renamed 'VL.LegendType' and its constructors+--   have been renamed 'VL.GradientLegend' and 'VL.SymbolLegend'.
+ src/Graphics/Vega/VegaLite/Configuration.hs view
@@ -0,0 +1,1444 @@+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Configuration+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : OverloadedStrings++Top-level configuration options. As this can configure most+of a visualization, it needs to import most of the other+modules.++-}++module Graphics.Vega.VegaLite.Configuration+       ( ConfigurationProperty(..)+       , FieldTitleProperty(..)++       , ViewConfig(..)+       , FacetConfig(..)+       , ConcatConfig(..)+       , ScaleConfig(..)+       , RangeConfig(..)+       , AxisConfig(..)+       , LegendConfig(..)+       , TitleConfig(..)++       , TitleFrame(..)++       , configuration+       , title++       ) where+++import qualified Data.Aeson as A+import qualified Data.Text as T++import Data.Aeson ((.=), object)+++import Graphics.Vega.VegaLite.Core+  ( schemeProperty+  )+import Graphics.Vega.VegaLite.Foundation+  ( Angle+  , Color+  , CompositionAlignment+  , DashStyle+  , DashOffset+  , APosition+  , FontWeight+  , Opacity+  , Orientation+  , OverlapStrategy+  , Side+  , StrokeCap+  , StrokeJoin+  , Symbol+  , HAlign+  , VAlign+  , BandAlign+  , Padding+  , Autosize+  , ZIndex+  , HeaderProperty+  , ViewBackground+  , fromColor+  , fromDS+  , splitOnNewline+  , header_+  , anchorLabel+  , fontWeightSpec+  , orientationSpec+  , hAlignLabel+  , vAlignLabel+  , bandAlignLabel+  , strokeCapLabel+  , strokeJoinLabel+  , sideLabel+  , overlapStrategyLabel+  , symbolLabel+  , compositionAlignmentSpec+  , paddingSpec+  , autosizeProperty+  , viewBackgroundSpec+  )+import Graphics.Vega.VegaLite.Geometry+  ( ProjectionProperty+  , projectionProperty+  )+import Graphics.Vega.VegaLite.Legend+  ( LegendLayout+  , LegendOrientation+  , legendOrientLabel+  , legendLayoutSpec+  )+import Graphics.Vega.VegaLite.Mark+  ( MarkProperty+  , mprops_+  )++import Graphics.Vega.VegaLite.Selection+  ( Selection+  , SelectionProperty+  , selectionProperties+  , selectionLabel+  )+import Graphics.Vega.VegaLite.Specification+  ( VLSpec+  , VLProperty(VLTitle)+  , ConfigureSpec(..)+  , BuildConfigureSpecs+  , LabelledSpec+  , PropertySpec+  )+  ++{-|++Type of configuration property to customise. See the+<https://vega.github.io/vega-lite/docs/config.html Vega-Lite documentation>+for details.++Used by 'configuration'.++In @version 0.5.0.0@:++- the @RemoveInvalid@ constructor was removed, as+the new 'Graphics.Vega.VegaLite.MRemoveInvalid' constructor for the+'Graphics.Vega.VegaLite.MarkProperty' type should be used instead+(so @'configuration' (RemoveInvalid b)@ changes to+@'configuration' ('Graphics.Vega.VegaLite.MarkStyle' ['Graphics.Vega.VegaLite.MRemoveInvalid' b])@.++- the @Stack@ constructor (which was called @StackProperty@ prior+  to version @0.4.0.0@) was removed.++-}++-- based on schema 3.3.0 #/definitions/Config+--+-- TODO:+--   Bar - change to BarConfig rather than MarkProperty?+--     BoxplotStyle BoxPlotConfig+--     Concat CompositionConfig+--     ErrorBand ErrorBandCOnfig+--     ErrorBar ErrorBarCOnfig+--   Facet takes CompositionConfig not FacetConfig+--     HeaderColumn takes HeaderConfig, just as HeaderStyle does+--     HeaderFacet ditto+--     HeaderRow ditto+--   LineStyle takes LineConfig not MarkConfig+--   TextStyle takes TextConfig not MarkConfig+--   TickStyle takes TickConfig not MarkConfig+--   TrailStyle takes LineConfig not MarkConfig+--++data ConfigurationProperty+    = AreaStyle [MarkProperty]+      -- ^ The default appearance of area marks.+    | Autosize [Autosize]+      -- ^ The default sizing of visualizations.+    | Axis [AxisConfig]+      -- ^ The default appearance of axes.+    | AxisBand [AxisConfig]+      -- ^ The default appearance of axes with band scaling.+    | AxisBottom [AxisConfig]+      -- ^ The default appearance of the bottom-side axes.+    | AxisLeft [AxisConfig]+      -- ^ The default appearance of the left-side axes.+    | AxisRight [AxisConfig]+      -- ^ The default appearance of the right-side axes.+    | AxisTop [AxisConfig]+      -- ^ The default appearance of the top-side axes.+    | AxisX [AxisConfig]+      -- ^ The default appearance of the X axes.+    | AxisY [AxisConfig]+      -- ^ The default appearance of the Y axes.+    | Background Color+      -- ^ The default background color of visualizations.+      --+      --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    | BarStyle [MarkProperty]+      -- ^ The default appearance of bar marks.+    | CircleStyle [MarkProperty]+      -- ^ The default appearance of circle marks.+    | ConcatStyle [ConcatConfig]+      -- ^ The default appearance of concatenated layouts.+      --+      --   @since 0.4.0.0+    | CountTitle T.Text+      -- ^ The default title style for count fields.+    | FacetStyle [FacetConfig]+      -- ^ The default appearance of facet layouts.+      --+      --   @since 0.4.0.0+    | FieldTitle FieldTitleProperty+      -- ^ The default title-generation style for fields.+    | GeoshapeStyle [MarkProperty]+      -- ^ The default appearance of geoshape marks.+      --+      --   @since 0.4.0.0+    | HeaderStyle [HeaderProperty]+      -- ^ The default appearance of facet headers.+      --+      --   @since 0.4.0.0+    | Legend [LegendConfig]+      -- ^ The default appearance of legends.+    | LineStyle [MarkProperty]+      -- ^ The default appearance of line marks.+    | MarkStyle [MarkProperty]+      -- ^ The default mark appearance.+    | NamedStyle T.Text [MarkProperty]+      -- ^ The default appearance of a single named style.+    | NamedStyles [(T.Text, [MarkProperty])]+      -- ^ The default appearance of a list of named styles.+      --+      --   @since 0.4.0.0+    | NumberFormat T.Text+      -- ^ The default number formatting for axis and text labels.+    | Padding Padding+      -- ^ The default padding in pixels from the edge of the of visualization+      --   to the data rectangle.+    | PointStyle [MarkProperty]+      -- ^ The default appearance of point marks.+    | Projection [ProjectionProperty]+      -- ^ The default style of map projections.+    | Range [RangeConfig]+      -- ^ The default range properties used when scaling.+    | RectStyle [MarkProperty]+      -- ^ The default appearance of rectangle marks.+    | RuleStyle [MarkProperty]+      -- ^ The default appearance of rule marks.+    | Scale [ScaleConfig]   -- TODO: rename ScaleStyle+      -- ^ The default properties used when scaling.+    | SelectionStyle [(Selection, [SelectionProperty])]+      -- ^ The default appearance of selection marks.+    | SquareStyle [MarkProperty]+      -- ^  the default appearance of square marks+    | TextStyle [MarkProperty]+      -- ^ The default appearance of text marks.+    | TickStyle [MarkProperty]+      -- ^ The default appearance of tick marks.+    | TimeFormat T.Text+      -- ^ The default time format for axis and legend labels.+    | TitleStyle [TitleConfig]+      -- ^ The default appearance of visualization titles.+    | TrailStyle [MarkProperty]+      -- ^ The default style of trail marks.+      --+      --   @since 0.4.0.0+    | View [ViewConfig]+      -- ^ The default single view style.++-- easier to turn into a ConfigSpec in config than here+configProperty :: ConfigurationProperty -> LabelledSpec+configProperty (Autosize aus) = "autosize" .= object (map autosizeProperty aus)+configProperty (Background bg) = "background" .= bg+configProperty (CountTitle ttl) = "countTitle" .= ttl+configProperty (ConcatStyle cps) = "concat" .= object (map concatConfigProperty cps)+configProperty (FieldTitle ftp) = "fieldTitle" .= fieldTitleLabel ftp+configProperty (NumberFormat fmt) = "numberFormat" .= fmt+configProperty (Padding pad) = "padding" .= paddingSpec pad+configProperty (TimeFormat fmt) = "timeFormat" .= fmt+configProperty (Axis acs) = "axis" .= object (map axisConfigProperty acs)+configProperty (AxisX acs) = "axisX" .= object (map axisConfigProperty acs)+configProperty (AxisY acs) = "axisY" .= object (map axisConfigProperty acs)+configProperty (AxisLeft acs) = "axisLeft" .= object (map axisConfigProperty acs)+configProperty (AxisRight acs) = "axisRight" .= object (map axisConfigProperty acs)+configProperty (AxisTop acs) = "axisTop" .= object (map axisConfigProperty acs)+configProperty (AxisBottom acs) = "axisBottom" .= object (map axisConfigProperty acs)+configProperty (AxisBand acs) = "axisBand" .= object (map axisConfigProperty acs)+configProperty (Legend lcs) = "legend" .= object (map legendConfigProperty lcs)+configProperty (MarkStyle mps) = mprops_ "mark" mps+configProperty (Projection pps) = "projection" .= object (map projectionProperty pps)+configProperty (AreaStyle mps) = mprops_ "area" mps+configProperty (BarStyle mps) = mprops_ "bar" mps+configProperty (CircleStyle mps) = mprops_ "circle" mps+configProperty (FacetStyle fps) = "facet" .= object (map facetConfigProperty fps)+configProperty (GeoshapeStyle mps) = mprops_ "geoshape" mps+configProperty (HeaderStyle hps) = header_ hps+configProperty (LineStyle mps) = mprops_ "line" mps+configProperty (PointStyle mps) = mprops_ "point" mps+configProperty (RectStyle mps) = mprops_ "rect" mps+configProperty (RuleStyle mps) = mprops_ "rule" mps+configProperty (SquareStyle mps) = mprops_ "square" mps+configProperty (TextStyle mps) = mprops_ "text" mps+configProperty (TickStyle mps) = mprops_ "tick" mps+configProperty (TitleStyle tcs) = "title" .= object (map titleConfigSpec tcs)+configProperty (NamedStyle nme mps) = "style" .= object [mprops_ nme mps]+configProperty (NamedStyles styles) =+  let toStyle = uncurry mprops_+  in "style" .= object (map toStyle styles)+configProperty (Scale scs) = scaleConfig_ scs+configProperty (Range rcs) = "range" .= object (map rangeConfigProperty rcs)+configProperty (SelectionStyle selConfig) =+  let selProp (sel, sps) = selectionLabel sel .= object (concatMap selectionProperties sps)+  in "selection" .= object (map selProp selConfig)+configProperty (TrailStyle mps) = mprops_ "trail" mps+configProperty (View vcs) = "view" .= object (concatMap viewConfigProperties vcs)+++{-|++Scale configuration property. These are used to configure all scales.+For more details see the+<https://vega.github.io/vega-lite/docs/scale.html#scale-config Vega-Lite documentation>.++Version @0.5.0.0@ removed the @SCRangeStep@ and @SCTextXRangeStep@+constructors. The new 'ViewStep' constructor of 'ViewConfig' should+be used instead.+-}++data ScaleConfig+    = SCBandPaddingInner Double+      -- ^ Default inner padding for x and y band-ordinal scales.+    | SCBandPaddingOuter Double+      -- ^ Default outer padding for x and y band-ordinal scales.+    | SCBarBandPaddingInner Double+      -- ^ Default inner padding for x and y band-ordinal scales of 'Graphics.Vega.VegaLite.Bar' marks.+      --+      --   @since 0.4.0.0+    | SCBarBandPaddingOuter Double+      -- ^ Default outer padding for x and y band-ordinal scales of 'Graphics.Vega.VegaLite.Bar' marks.+      --+      --   @since 0.4.0.0+    | SCRectBandPaddingInner Double+      -- ^ Default inner padding for x and y band-ordinal scales of 'Graphics.Vega.VegaLite.Rect' marks.+      --+      --   @since 0.4.0.0+    | SCRectBandPaddingOuter Double+      -- ^ Default outer padding for x and y band-ordinal scales of 'Graphics.Vega.VegaLite.Rect' marks.+      --+      --   @since 0.4.0.0+    | SCClamp Bool+      -- ^ Whether or not by default values that exceed the data domain are clamped to+      --   the min/max range value.+    | SCMaxBandSize Double+      -- ^ Default maximum value for mapping quantitative fields to a bar's+      --   size/bandSize.+    | SCMinBandSize Double+      -- ^ Default minimum value for mapping quantitative fields to a bar's+      --   size/bandSize.+    | SCMaxFontSize Double+      -- ^ Default maximum value for mapping a quantitative field to a text+      --   mark's size.+    | SCMinFontSize Double+      -- ^ Default minimum value for mapping a quantitative field to a text+      --   mark's size.+    | SCMaxOpacity Opacity+      -- ^ Default maximum opacity for mapping a field to opacity.+    | SCMinOpacity Opacity+      -- ^ Default minimum opacity for mapping a field to opacity.+    | SCMaxSize Double+      -- ^ Default maximum size for point-based scales.+    | SCMinSize Double+      -- ^ Default minimum size for point-based scales.+    | SCMaxStrokeWidth Double+      -- ^ Default maximum stroke width for rule, line and trail marks.+    | SCMinStrokeWidth Double+      -- ^ Default minimum stroke width for rule, line and trail marks.+    | SCPointPadding Double+      -- ^ Default padding for point-ordinal scales.+    | SCRound Bool+      -- ^ Are numeric values are rounded to integers when scaling? Useful+      --   for snapping to the pixel grid.+    | SCUseUnaggregatedDomain Bool+      -- ^ Whether or not to use the source data range before aggregation.+++scaleConfig_ :: [ScaleConfig] -> LabelledSpec+-- scaleConfig_ [] = "scale" .= A.Null  -- not sure here+scaleConfig_ scs = "scale" .= object (map scaleConfigProperty scs)+++-- | Indicates the style in which field names are displayed.++data FieldTitleProperty+    = Verbal+      -- ^ Creates \"Sum of field\", \"Year of date\", \"field (binned)\", etc.+    | Function+      -- ^ Creates \"SUM(field)\", \"YEAR(date)\", \"BIN(field)\", etc.+    | Plain+      -- ^ Just use the field name without any extra text.+++fieldTitleLabel :: FieldTitleProperty -> T.Text+fieldTitleLabel Verbal = "verbal"+fieldTitleLabel Function = "functional"+fieldTitleLabel Plain = "plain"+++{-|++Legend configuration options, set with the 'Legend' constructor.+For more detail see the+<https://vega.github.io/vega-lite/docs/legend.html#config Vega-Lite documentation>.++This data type has seen significant changes in the @0.4.0.0@ release:++- the @EntryPadding@, @GradientHeight@, @GradientLabelBaseline@, @GradientWidth@+  and @SymbolColor@ constructors were removed;++- the constructors were removed;++- the remaining constructors that did not begin with @Le@ were renamed (for+  example @Orient@ was changed to 'LeOrient');++- and new constructors were added.++In @0.5.0.0@ the @LeShortTimeLabels@ constructor was removed.++-}++-- based on schema 3.3.0 #/definitions/LegendConfig++data LegendConfig+    = LeClipHeight Double+      -- ^ The height in pixels at which to clip symbol legend entries.+      --+      --   @since 0.4.0.0+    | LeColumnPadding Double+      -- ^ The horizontal padding, in pixels, between symbol legend entries.+      --+      --   @since 0.4.0.0+    | LeColumns Int+      -- ^ The number of columns in which to arrange symbol legend entries. A value+      --   of @0@ or lower indicates a single row with one column per entry.+      --+      --   @since 0.4.0.0+    | LeCornerRadius Double+      -- ^ The corner radius for the full legend.+    | LeFillColor Color+      -- ^ The background fill color for the full legend.+    | LeGradientDirection Orientation+      -- ^ The default direction for gradient legends.+      --+      --   @since 0.4.0.0+    | LeGradientHorizontalMaxLength Double+      -- ^ The maximum legend length for a horizontal gradient.+      --+      --   @since 0.4.0.0+    | LeGradientHorizontalMinLength Double+      -- ^ The minimum legend length for a horizontal gradient.+      --+      --   @since 0.4.0.0+    | LeGradientLabelLimit Double+      -- ^ The maximum allowed length, in pixels, of color-ramp gradient labels.+    | LeGradientLabelOffset Double+      -- ^ The vertical offset in pixels for color-ramp gradient labels.+    | LeGradientLength Double+      -- ^ The length in pixels of the primary axis of a color gradient.+      --   See also 'LeGradientThickness'.+      --+      --   @since 0.4.0.0+    | LeGradientOpacity Opacity+      -- ^ The opacity of the color gradient.+      --+      --   @since 0.4.0.0+    | LeGradientStrokeColor Color+      -- ^ The color of the gradient stroke.+    | LeGradientStrokeWidth Double+      -- ^ The width of the gradient stroke, in pixels.+    | LeGradientThickness Double+      -- ^ The thickness in pixels of the color gradient. See also 'LeGradientLength'.+      --+      --   @since 0.4.0.0+    | LeGradientVerticalMaxLength Double+      -- ^ The maximum legend length for a vertical gradient.+      --+      --   @since 0.4.0.0+    | LeGradientVerticalMinLength Double+      -- ^ The minimum legend length for a vertical gradient.+      --+      --   @since 0.4.0.0+    | LeGridAlign CompositionAlignment+      -- ^ The alignment to apply to symbol legends rows and columns.+      --+      --    @since 0.4.0.0+    | LeLabelAlign HAlign+      -- ^ The alignment of the legend label.+    | LeLabelBaseline VAlign+      -- ^ The position of the baseline of the legend label.+    | LeLabelColor Color+      -- ^ The color of the legend label.+    | LeLabelFont T.Text+      -- ^ The font of the legend label.+    | LeLabelFontSize Double+      -- ^ The font of the legend label.+    | LeLabelFontStyle T.Text+      -- ^ The font style of the legend label.+      --+      --   @since 0.4.0.0+    | LeLabelFontWeight FontWeight+      -- ^ The font weight of the legend label.+      --+      --   @since 0.4.0.0+    | LeLabelLimit Double+      -- ^ The maxumum allowed pixel width of the legend label.+    | LeLabelOffset Double+      -- ^ The offset of the legend label.+    | LeLabelOpacity Opacity+      -- ^ The opacity of the legend label.+      --+      --   @since 0.4.0.0+    | LeLabelOverlap OverlapStrategy+      -- ^ How to resolve overlap of labels in gradient legends.+      --+      --   @since 0.4.0.0+    | LeLabelPadding Double+      -- ^ The passing in pixels between the legend and legend labels.+      --+      --   @since 0.4.0.0+    | LeLabelSeparation Double+      -- ^ The minimum separation between label bounding boxes for them+      --   to be considered non-overlapping (ignored if 'Graphics.Vega.VegaLite.ONone' is the+      --   chosen overlap strategy).+      --+      --   @since 0.4.0.0+    | LeLayout [LegendLayout]+      -- ^ Layout parameters for the legend orient group.+      --+      --   @since 0.4.0.0+     | LeLeX Double+      -- ^ Custom x position for a legend with orientation 'Graphics.Vega.VegaLite.LONone'.+      --+      --   @since 0.4.0.0+     | LeLeY Double+      -- ^ Custom y position for a legend with orientation 'Graphics.Vega.VegaLite.LONone'.+      --+      --   @since 0.4.0.0+    | LeOffset Double+      -- ^ The offset in pixels between the legend and the data rectangle+      --   and axes.+    | LeOrient LegendOrientation+      -- ^ The orientation of the legend.+    | LePadding Double+      -- ^ The padding between the border and content of the legend group.+    | LeRowPadding Double+      -- ^ The vertical padding in pixels between symbol legend entries.+      --+      --   @since 0.4.0.0+    | LeStrokeColor Color+      -- ^ The border stoke color for the full legend.+    | LeStrokeDash DashStyle+      -- ^ The border stroke dash pattern for the full legend.+    | LeStrokeWidth Double+      -- ^ The border stroke width for the full legend.+    | LeSymbolBaseFillColor Color+      -- ^ The fill color for legend symbols. This is only applied if+      --   there is no \"fill\" scale color encoding for the legend.+      --+      --   @since 0.4.0.0+    | LeSymbolBaseStrokeColor Color+      -- ^ The stroke color for legend symbols. This is only applied if+      --   there is no \"fill\" scale color encoding for the legend.+      --+      --   @since 0.4.0.0+    | LeSymbolDash DashStyle+      -- ^ The pattern for dashed symbol strokes.+      --+      --   @since 0.4.0.0+    | LeSymbolDashOffset DashOffset+      -- ^ The offset at which to start drawing the symbol dash pattern.+      --+      --   @since 0.4.0.0+    | LeSymbolDirection Orientation+      -- ^ The default direction for symbol legends.+      --+      --   @since 0.4.0.0+    | LeSymbolFillColor Color+      -- ^ The color of the legend symbol.+      --+      --   @since 0.4.0.0+    | LeSymbolOffset Double+      -- ^ The horizontal pixel offset for legend symbols.+      --+      --   @since 0.4.0.0+    | LeSymbolOpacity Opacity+      -- ^ The opacity of the legend symbols.+      --+      --   @since 0.4.0.0+    | LeSymbolSize Double+      -- ^ The size of the legend symbol, in pixels.+    | LeSymbolStrokeColor Color+      -- ^ The stroke color for legend symbols.+      --+      --   @since 0.4.0.0+    | LeSymbolStrokeWidth Double+      -- ^ The width of the symbol's stroke.+    | LeSymbolType Symbol+      -- ^ The default shape type for legend symbols.+    | LeTitle T.Text+      -- ^ The legend title.+      --+      --   @since 0.4.0.0+    | LeNoTitle+      -- ^ Draw no title for the legend.+      --+      --   @since 0.4.0.0+    | LeTitleAlign HAlign+      -- ^ The horizontal text alignment for legend titles.+    | LeTitleAnchor APosition+      -- ^ The text anchor position for legend titles.+      --+      --   @since 0.4.0.0+    | LeTitleBaseline VAlign+      -- ^ The vertical text alignment for legend titles.+    | LeTitleColor Color+      -- ^ The color of the legend title.+    | LeTitleFont T.Text+      -- ^ The font of the legend title.+    | LeTitleFontSize Double+      -- ^ The font size of the legend title.+    | LeTitleFontStyle T.Text+      -- ^ The font style for the legend title.+      --+      --   @since 0.4.0.0+    | LeTitleFontWeight FontWeight+      -- ^ The font weight of the legend title.+    | LeTitleLimit Double+      -- ^ The maxmimum pixel width of the legend title.+    | LeTitleOpacity Opacity+      -- ^ The opacity of the legend title.+      --+      --   @since 0.4.0.0+    | LeTitleOrient Side+      -- ^ The orientation of the legend title.+      --+      --   @since 0.4.0.0+    | LeTitlePadding Double+      -- ^ The padding, in pixels, between title and legend.+++legendConfigProperty :: LegendConfig -> LabelledSpec+legendConfigProperty (LeClipHeight x) = "clipHeight" .= x+legendConfigProperty (LeColumnPadding x) = "columnPadding" .= x+legendConfigProperty (LeColumns n) = "columns" .= n+legendConfigProperty (LeCornerRadius x) = "cornerRadius" .= x+legendConfigProperty (LeFillColor s) = "fillColor" .= fromColor s+legendConfigProperty (LeGradientDirection o) = "gradientDirection" .= orientationSpec o+legendConfigProperty (LeGradientHorizontalMaxLength x) = "gradientHorizontalMaxLength" .= x+legendConfigProperty (LeGradientHorizontalMinLength x) = "gradientHorizontalMinLength" .= x+legendConfigProperty (LeGradientLabelLimit x) = "gradientLabelLimit" .= x+legendConfigProperty (LeGradientLabelOffset x) = "gradientLabelOffset" .= x+legendConfigProperty (LeGradientLength x) = "gradientLength" .= x+legendConfigProperty (LeGradientOpacity x) = "gradientOpacity" .= x+legendConfigProperty (LeGradientStrokeColor s) = "gradientStrokeColor" .= fromColor s+legendConfigProperty (LeGradientStrokeWidth x) = "gradientStrokeWidth" .= x+legendConfigProperty (LeGradientThickness x) = "gradientThickness" .= x+legendConfigProperty (LeGradientVerticalMaxLength x) = "gradientVerticalMaxLength" .= x+legendConfigProperty (LeGradientVerticalMinLength x) = "gradientVerticalMinLength" .= x+legendConfigProperty (LeGridAlign ga) = "gridAlign" .= compositionAlignmentSpec ga+legendConfigProperty (LeLabelAlign ha) = "labelAlign" .= hAlignLabel ha+legendConfigProperty (LeLabelBaseline va) = "labelBaseline" .= vAlignLabel va+legendConfigProperty (LeLabelColor s) = "labelColor" .= fromColor s+legendConfigProperty (LeLabelFont s) = "labelFont" .= s+legendConfigProperty (LeLabelFontSize x) = "labelFontSize" .= x+legendConfigProperty (LeLabelFontStyle s) = "labelFontStyle" .= s+legendConfigProperty (LeLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw+legendConfigProperty (LeLabelLimit x) = "labelLimit" .= x+legendConfigProperty (LeLabelOffset x) = "labelOffset" .= x+legendConfigProperty (LeLabelOpacity x) = "labelOpacity" .= x+legendConfigProperty (LeLabelOverlap olap) = "labelOverlap" .= overlapStrategyLabel olap+legendConfigProperty (LeLabelPadding x) = "labelPadding" .= x+legendConfigProperty (LeLabelSeparation x) = "labelSeparation" .= x+legendConfigProperty (LeLayout ll) = "layout" .= object (map legendLayoutSpec ll)+legendConfigProperty (LeLeX x) = "legendX" .= x+legendConfigProperty (LeLeY x) = "legendY" .= x+legendConfigProperty (LeOffset x) = "offset" .= x+legendConfigProperty (LeOrient orl) = "orient" .= legendOrientLabel orl+legendConfigProperty (LePadding x) = "padding" .= x+legendConfigProperty (LeRowPadding x) = "rowPadding" .= x+legendConfigProperty (LeStrokeColor s) = "strokeColor" .= fromColor s+legendConfigProperty (LeStrokeDash xs) = "strokeDash" .= fromDS xs+legendConfigProperty (LeStrokeWidth x) = "strokeWidth" .= x+legendConfigProperty (LeSymbolBaseFillColor s) = "symbolBaseFillColor" .= fromColor s+legendConfigProperty (LeSymbolBaseStrokeColor s) = "symbolBaseStrokeColor" .= fromColor s+legendConfigProperty (LeSymbolDash xs) = "symbolDash" .= fromDS xs+legendConfigProperty (LeSymbolDashOffset x) = "symbolDashOffset" .= x+legendConfigProperty (LeSymbolDirection o) = "symbolDirection" .= orientationSpec o+legendConfigProperty (LeSymbolFillColor s) = "symbolFillColor" .= fromColor s+legendConfigProperty (LeSymbolOffset x) = "symbolOffset" .= x+legendConfigProperty (LeSymbolOpacity x) = "symbolOpacity" .= x+legendConfigProperty (LeSymbolSize x) = "symbolSize" .= x+legendConfigProperty (LeSymbolStrokeColor s) = "symbolStrokeColor" .= fromColor s+legendConfigProperty (LeSymbolStrokeWidth x) = "symbolStrokeWidth" .= x+legendConfigProperty (LeSymbolType s) = "symbolType" .= symbolLabel s+legendConfigProperty (LeTitle s) = "title" .= s+legendConfigProperty LeNoTitle = "title" .= A.Null+legendConfigProperty (LeTitleAlign ha) = "titleAlign" .= hAlignLabel ha+legendConfigProperty (LeTitleAnchor anc) = "titleAnchor" .= anchorLabel anc+legendConfigProperty (LeTitleBaseline va) = "titleBaseline" .= vAlignLabel va+legendConfigProperty (LeTitleColor s) = "titleColor" .= fromColor s+legendConfigProperty (LeTitleFont s) = "titleFont" .= s+legendConfigProperty (LeTitleFontSize x) = "titleFontSize" .= x+legendConfigProperty (LeTitleFontStyle s) = "titleFontStyle" .= s+legendConfigProperty (LeTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw+legendConfigProperty (LeTitleLimit x) = "titleLimit" .= x+legendConfigProperty (LeTitleOpacity x) = "titleOpacity" .= x+legendConfigProperty (LeTitleOrient orient) = "titleOrient" .= sideLabel orient+legendConfigProperty (LeTitlePadding x) = "titlePadding" .= x+++{-|++Properties for customising the colors of a range. The parameter should be a+named color scheme such as @\"accent\"@ or @\"purpleorange-11\"@. For details see the+<https://vega.github.io/vega/docs/schemes/#scheme-properties Vega-Lite documentation>.+-}+data RangeConfig+    = RCategory T.Text+    | RDiverging T.Text+    | RHeatmap T.Text+    | ROrdinal T.Text+    | RRamp T.Text+    | RSymbol T.Text+++rangeConfigProperty :: RangeConfig -> LabelledSpec+rangeConfigProperty rangeCfg =+  let (l, n) = case rangeCfg of+        RCategory nme -> ("category", nme)+        RDiverging nme -> ("diverging", nme)+        RHeatmap nme -> ("heatmap", nme)+        ROrdinal nme -> ("ordinal", nme)+        RRamp nme -> ("ramp", nme)+        RSymbol nme -> ("symbol", nme)++  in l .= object [schemeProperty n []]+++scaleConfigProperty :: ScaleConfig -> LabelledSpec+scaleConfigProperty (SCBandPaddingInner x) = "bandPaddingInner" .= x+scaleConfigProperty (SCBandPaddingOuter x) = "bandPaddingOuter" .= x+scaleConfigProperty (SCBarBandPaddingInner x) = "barBandPaddingInner" .= x+scaleConfigProperty (SCBarBandPaddingOuter x) = "barBandPaddingOuter" .= x+scaleConfigProperty (SCRectBandPaddingInner x) = "rectBandPaddingInner" .= x+scaleConfigProperty (SCRectBandPaddingOuter x) = "rectBandPaddingOuter" .= x+scaleConfigProperty (SCClamp b) = "clamp" .= b+scaleConfigProperty (SCMaxBandSize x) = "maxBandSize" .= x+scaleConfigProperty (SCMinBandSize x) = "minBandSize" .= x+scaleConfigProperty (SCMaxFontSize x) = "maxFontSize" .= x+scaleConfigProperty (SCMinFontSize x) = "minFontSize" .= x+scaleConfigProperty (SCMaxOpacity x) = "maxOpacity" .= x+scaleConfigProperty (SCMinOpacity x) = "minOpacity" .= x+scaleConfigProperty (SCMaxSize x) = "maxSize" .= x+scaleConfigProperty (SCMinSize x) = "minSize" .= x+scaleConfigProperty (SCMaxStrokeWidth x) = "maxStrokeWidth" .= x+scaleConfigProperty (SCMinStrokeWidth x) = "minStrokeWidth" .= x+scaleConfigProperty (SCPointPadding x) = "pointPadding" .= x+scaleConfigProperty (SCRound b) = "round" .= b+scaleConfigProperty (SCUseUnaggregatedDomain b) = "useUnaggregatedDomain" .= b+++{-|++View configuration property. These are used to configure the style of a single+view within a visualization such as its size and default fill and stroke colors.+For further details see the+<https://vega.github.io/vega-lite/docs/spec.html#config Vega-Lite documentation>.++In version @0.5.0.0@ the @ViewWidth@ and @ViewHeight@ constructors have+been deprecated, and replaced by+'ViewContinuousWidth', 'ViewContinuousHeight',+'ViewDiscreteWidth', and 'ViewDiscreteHeight'. The 'ViewBackgroundStyle'+constructor has been added.++This type has been changed in the @0.4.0.0@ release to use a consistent+naming scheme for the constructors (everything starts with @View@). Prior to+this release only @ViewWidth@ and @ViewHeight@ were named this way. There+are also five new constructors.++-}++-- based on schema 3.3.0 #/definitions/ViewConfig++{-# DEPRECATED ViewWidth "Please change ViewWidth to ViewContinuousWidth" #-}+{-# DEPRECATED ViewHeight "Please change ViewHeight to ViewContinuousHeight" #-}+data ViewConfig+    = ViewBackgroundStyle [ViewBackground]+      -- ^ The default single-view style.+      --+      --   @since 0.5.0.0+    | ViewClip Bool+      -- ^ Should the view be clipped?+    | ViewContinuousWidth Double+      -- ^ The default width of single views when the+      --   visualization has a continuous x field.+      --+      --   @since 0.5.0.0+    | ViewContinuousHeight Double+      -- ^ The default height of single views when the+      --   visualization has a continuous y field.+      --+      --   @since 0.5.0.0+    | ViewCornerRadius Double+      -- ^ The radius, in pixels, of rounded rectangle corners.+      --+      --   The default is @0@.+      --+      --   @since 0.4.0.0+    | ViewDiscreteWidth Double+      -- ^ The default width of single views when the+      --   visualization has a discrete x field.+      --+      --   @since 0.5.0.0+    | ViewDiscreteHeight Double+      -- ^ The default height of single views when the+      --   visualization has a discrete y field.+      --+      --   @since 0.5.0.0+    | ViewFill (Maybe Color)+      -- ^ The fill color.+      --+      --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    | ViewFillOpacity Opacity+      -- ^ The fill opacity.+    | ViewOpacity Opacity+      -- ^ The overall opacity.+      --+      --   The default is @0.7@ for non-aggregate plots with 'Graphics.Vega.VegaLite.Point', 'Graphics.Vega.VegaLite.Tick',+      --   'Graphics.Vega.VegaLite.Circle', or 'Graphics.Vega.VegaLite.Square' marks or layered 'Graphics.Vega.VegaLite.Bar' charts, and @1@+      --   otherwise.+      --+      --   @since 0.4.0.0+    | ViewStep Double+      -- ^ Default step size for discrete fields.+      --+      --   This replaces @SCRangeStep@ and @SCTextXRangeStep@ from+      --   'ScaleConfig'.+      --+      --   @since 0.5.0.0+    | ViewStroke (Maybe Color)+      -- ^ The stroke color.+      --+      --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    | ViewStrokeCap StrokeCap+      -- ^ The stroke cap for line-ending style.+      --+      --   @since 0.4.0.0+    | ViewStrokeDash DashStyle+      -- ^ The stroke dash pattern.+    | ViewStrokeDashOffset DashOffset+      -- ^ The offset for the dash pattern.+    | ViewStrokeJoin StrokeJoin+      -- ^ The stroke line-join method.+      --+      --   @since 0.4.0.0+    | ViewStrokeMiterLimit Double+      -- ^ The miter limit at which to bevel a line join.+      --+      --   @since 0.4.0.0+    | ViewStrokeOpacity Opacity+      -- ^ The stroke opacity.+    | ViewStrokeWidth Double+      -- ^ The stroke width, in pixels.+    | ViewWidth Double+      -- ^ As of version @0.5.0.0@ this is deprecated and 'ViewContinuousWidth' should+      --   be used instead.+    | ViewHeight Double+      -- ^ As of version @0.5.0.0@ this is deprecated and 'ViewContinuousHeight' should+      --   be used instead.+++viewConfigProperties :: ViewConfig -> [LabelledSpec]+viewConfigProperties (ViewBackgroundStyle bs) = map viewBackgroundSpec bs+viewConfigProperties (ViewClip b) = ["clip" .= b]+viewConfigProperties (ViewWidth x) = ["continuousWidth" .= x]+viewConfigProperties (ViewHeight x) = ["continuousHeight" .= x]+viewConfigProperties (ViewContinuousWidth x) = ["continuousWidth" .= x]+viewConfigProperties (ViewContinuousHeight x) = ["continuousHeight" .= x]+viewConfigProperties (ViewCornerRadius x) = ["cornerRadius" .= x]+viewConfigProperties (ViewDiscreteWidth x) = ["discreteWidth" .= x]+viewConfigProperties (ViewDiscreteHeight x) = ["discreteHeight" .= x]+viewConfigProperties (ViewFill ms) = ["fill" .= maybe A.Null fromColor ms]+viewConfigProperties (ViewFillOpacity x) = ["fillOpacity" .= x]+viewConfigProperties (ViewOpacity x) = ["opacity" .= x]+viewConfigProperties (ViewStep x) = ["step" .= x]+viewConfigProperties (ViewStroke ms) = ["stroke" .= maybe A.Null fromColor ms]+viewConfigProperties (ViewStrokeCap sc) = ["strokeCap" .= strokeCapLabel sc]+viewConfigProperties (ViewStrokeDash xs) = ["strokeDash" .= fromDS xs]+viewConfigProperties (ViewStrokeDashOffset x) = ["strokeDashOffset" .= x]+viewConfigProperties (ViewStrokeJoin sj) = ["strokeJoin" .= strokeJoinLabel sj]+viewConfigProperties (ViewStrokeMiterLimit x) = ["strokeMiterLimit" .= x]+viewConfigProperties (ViewStrokeOpacity x) = ["strokeOpacity" .= x]+viewConfigProperties (ViewStrokeWidth x) = ["strokeWidth" .= x]+++{-|++Axis configuration options for customising all axes. See the+<https://vega.github.io/vega-lite/docs/axis.html#general-config Vega-Lite documentation>+for more details.++This is used by 'ConfigurationProperty'.++The @TitleMaxLength@ constructor was removed in release @0.4.0.0@. The+@TitleLimit@ constructor should be used instead.++In @0.5.0.0@ the @ShortTimeLabels@ constructor was removed.++-}+data AxisConfig+    = BandPosition Double+      -- ^ The default axis band position.+    | Domain Bool+      -- ^ Should the axis domain be displayed?+    | DomainColor Color+      -- ^ The axis domain color.+    | DomainDash DashStyle+      -- ^ The dash pattern of the domain.+      --+      --   @since 0.4.0.0+    | DomainDashOffset DashOffset+      -- ^ The offset for the dash pattern.+      --+      --   @since 0.4.0.0+    | DomainOpacity Opacity+      -- ^ The axis domain opacity.+      --+      --   @since 0.4.0.0+    | DomainWidth Double+      -- ^ The width of the axis domain.+    | Grid Bool+      -- ^ Should an axis grid be displayed?+    | GridColor Color+      -- ^ The color for the grid.+    | GridDash DashStyle+      -- ^ The dash pattern of the grid.+    | GridDashOffset DashOffset+      -- ^ The offset for the dash pattern.+      --+      --   @since 0.4.0.0+    | GridOpacity Opacity+      -- ^ The opacity of the grid.+    | GridWidth Double+      -- ^ The width of the grid lines.+    | Labels Bool+      -- ^ Should labels be added to an axis?+    | LabelAlign HAlign+      -- ^ The horizontal alignment for labels.+      --+      --   @since 0.4.0.0+    | LabelAngle Angle+      -- ^ The angle at which to draw labels.+    | LabelBaseline VAlign+      -- ^ The vertical alignment for labels.+      --+      --   @since 0.4.0.0+    | LabelNoBound+      -- ^ No boundary overlap check is applied to labels. This is the+      --   default behavior.+      --+      --   See also 'LabelBound' and 'LabelBoundValue'.+      --+      --   @since 0.4.0.0+    | LabelBound+      -- ^ Labels are hidden if they exceed the axis range by more than 1+      --   pixel.+      --+      --   See also 'LabelNoBound' and 'LabelBoundValue'.+      --+      --   @since 0.4.0.0+    | LabelBoundValue Double+      -- ^ Labels are hidden if they exceed the axis range by more than+      --   the given number of pixels.+      --+      --   See also 'LabelNoBound' and 'LabelBound'.+      --+      --   @since 0.4.0.0+    | LabelColor Color+      -- ^ The label color.+    | LabelNoFlush+      -- ^ The labels are not aligned flush to the scale. This is the+      --   default for non-continuous X scales.+      --+      --   See also 'LabelFlush' and 'LabelFlushValue'.+      --+      --   @since 0.4.0.0+    | LabelFlush+      -- ^ The first and last axis labels are aligned flush to the scale+      --   range.+      --+      --   See also 'LabelNoFlush' and 'LabelFlushValue'.+      --+      --   @since 0.4.0.0+    | LabelFlushValue Double+      -- ^ The labels are aligned flush, and the parameter determines+      --   the extra offset, in pixels, to apply to the first and last+      --   labels. This can help the labels better group (visually) with+      --   the corresponding axis ticks.+      --+      --   See also 'LabelNoFlush' and 'LabelFlush'.+      --+      --   @since 0.4.0.0+    | LabelFlushOffset Double+      -- ^ The number of pixels to offset flush-adjusted labels.+      --+      --   @since 0.4.0.0+    | LabelFont T.Text+      -- ^ The font for the label.+    | LabelFontSize Double+      -- ^ The font size of the label.+    | LabelFontStyle T.Text+      -- ^ The font style of the label.+      --+      --   @since 0.4.0.0+    | LabelFontWeight FontWeight+      -- ^ The font weight of the label.+      --+      --   @since 0.4.0.0+    | LabelLimit Double+      -- ^ The maximum width of a label, in pixels.+    | LabelOpacity Opacity+      -- ^ The opacity of the label.+      --+      --   @since 0.4.0.0+    | LabelOverlap OverlapStrategy+      -- ^ How should overlapping labels be displayed?+    | LabelPadding Double+      -- ^ The padding, in pixels, between the label and the axis.+    | LabelSeparation Double+      -- ^ The minimum separation, in pixels, between label bounding boxes+      --   for them to be considered non-overlapping. This is ignored if+      --   the 'LabelOverlap' strategy is 'Graphics.Vega.VegaLite.ONone'.+      --+      --   @since 0.4.0.0+    | MaxExtent Double+      -- ^ The maximum extent, in pixels, that axis ticks and labels should use.+      --   This determines a maxmium offset value for axis titles.+    | MinExtent Double+      -- ^ The minimum extent, in pixels, that axis ticks and labels should use.+      --   This determines a minmium offset value for axis titles.+    | NoTitle+      -- ^ Do not draw a title for this axis.+      --+      --   @since 0.4.0.0+    | Orient Side+      -- ^ The orientation of the axis.+      --+      --   @since 0.4.0.0+    | Ticks Bool+      -- ^ Should tick marks be drawn on an axis?+    | TickBand BandAlign+      -- ^ For band scales, indicates if ticks and grid lines should be+      --   placed at the center of a band (the default) or at the band+      --   extents to indicate intervals.+      --+      --   @since 0.5.0.0+    | TickColor Color+      -- ^ The color of the ticks.+    | TickDash DashStyle+      -- ^ The dash pattern of the ticks.+    | TickDashOffset DashOffset+      -- ^ The offset for the dash pattern.+      --+      --   @since 0.4.0.0+    | TickExtra Bool+      -- ^ Should an extra axis tick mark be added for the initial position of+      --   the axis?+      --+      --   @since 0.4.0.0+    | TickOffset Double+      -- ^ The position offset, in pixels, to apply to ticks, labels, and grid lines.+      --+      --   @since 0.4.0.0+    | TickOpacity Opacity+      -- ^ The opacity of the ticks.+      --+      --   @since 0.4.0.0+    | TickRound Bool+      -- ^ Should pixel position values be rounded to the nearest integer?+    | TickSize Double+      -- ^ The size of the tick marks in pixels.+    | TickWidth Double+      -- ^ The width of the tick marks in pixels.+    | TitleAlign HAlign+      -- ^ The horizontal alignment of the axis title.+    | TitleAnchor APosition+      -- ^ The text anchor position for placing axis titles.+      --+      --   @since 0.4.0.0+    | TitleAngle Angle+      -- ^ The angle of the axis title.+    | TitleBaseline VAlign+      -- ^ The vertical alignment of the axis title.+    | TitleColor Color+      -- ^ The color of the axis title.+    | TitleFont T.Text+      -- ^ The font for the axis title.+    | TitleFontSize Double+      -- ^ The font size of the axis title.+    | TitleFontStyle T.Text+      -- ^ The font style of the axis title.+      --+      --   @since 0.4.0.0+    | TitleFontWeight FontWeight+      -- ^ The font weight of the axis title.+    | TitleLimit Double+      -- ^ The maximum allowed width of the axis title, in pixels.+    | TitleLineHeight Double+      -- ^ Line height, in pixels, for multi-line title text.+      --+      --   @since 0.5.0.0+    | TitleOpacity Opacity+      -- ^ The opacity of the axis title.+      --+      --   @since 0.4.0.0+    | TitlePadding Double+      -- ^ The padding, in pixels, between title and axis.+    | TitleX Double+      -- ^ The X coordinate of the axis title, relative to the axis group.+    | TitleY Double+      -- ^ The Y coordinate of the axis title, relative to the axis group.+    | TranslateOffset Double+      -- ^ The translation offset in pixels applied to the axis group+      --   mark x and y. If specified it overrides the default value+      --   of a 0.5 offset to pixel-align stroked lines.+      --+      --   @since 0.5.0.0+++axisConfigProperty :: AxisConfig -> LabelledSpec+axisConfigProperty (BandPosition x) = "bandPosition" .= x+axisConfigProperty (Domain b) = "domain" .= b+axisConfigProperty (DomainColor c) = "domainColor" .= fromColor c+axisConfigProperty (DomainDash ds) = "domainDash" .= fromDS ds+axisConfigProperty (DomainDashOffset x) = "domainDashOffset" .= x+axisConfigProperty (DomainOpacity x) = "domainOpacity" .= x+axisConfigProperty (DomainWidth w) = "domainWidth" .= w+axisConfigProperty (Grid b) = "grid" .= b+axisConfigProperty (GridColor c) = "gridColor" .= fromColor c+axisConfigProperty (GridDash ds) = "gridDash" .= fromDS ds+axisConfigProperty (GridDashOffset x) = "gridDashOffset" .= x+axisConfigProperty (GridOpacity o) = "gridOpacity" .= o+axisConfigProperty (GridWidth x) = "gridWidth" .= x+axisConfigProperty (LabelAlign ha) = "labelAlign" .= hAlignLabel ha+axisConfigProperty (LabelAngle angle) = "labelAngle" .= angle+axisConfigProperty (LabelBaseline va) = "labelBaseline" .= vAlignLabel va+axisConfigProperty LabelNoBound = "labelBound" .= False+axisConfigProperty LabelBound = "labelBound" .= True+axisConfigProperty (LabelBoundValue x) = "labelBound" .= x+axisConfigProperty (LabelColor c) = "labelColor" .= fromColor c+axisConfigProperty LabelNoFlush = "labelFlush" .= False+axisConfigProperty LabelFlush = "labelFlush" .= True+axisConfigProperty (LabelFlushValue x) = "labelFlush" .= x+axisConfigProperty (LabelFlushOffset x) = "labelFlushOffset" .= x+axisConfigProperty (LabelFont f) = "labelFont" .= f+axisConfigProperty (LabelFontSize x) = "labelFontSize" .= x+axisConfigProperty (LabelFontStyle s) = "labelFontStyle" .= s+axisConfigProperty (LabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw+axisConfigProperty (LabelLimit x) = "labelLimit" .= x+axisConfigProperty (LabelOpacity x) = "labelOpacity" .= x+axisConfigProperty (LabelOverlap strat) = "labelOverlap" .= overlapStrategyLabel strat+axisConfigProperty (LabelPadding pad) = "labelPadding" .= pad+axisConfigProperty (LabelSeparation x) = "labelSeparation" .= x+axisConfigProperty (Labels b) = "labels" .= b+axisConfigProperty (MaxExtent n) = "maxExtent" .= n+axisConfigProperty (MinExtent n) = "minExtent" .= n+axisConfigProperty (Orient orient) = "orient" .= sideLabel orient+axisConfigProperty (TickBand band) = "tickBand" .= bandAlignLabel band+axisConfigProperty (TickColor c) = "tickColor" .= fromColor c+axisConfigProperty (TickDash ds) = "tickDash" .= fromDS ds+axisConfigProperty (TickDashOffset x) = "tickDashOffset" .= x+axisConfigProperty (TickExtra b) = "tickExtra" .= b+axisConfigProperty (TickOffset x) = "tickOffset" .= x+axisConfigProperty (TickOpacity x) = "tickOpacity" .= x+axisConfigProperty (TickRound b) = "tickRound" .= b+axisConfigProperty (TickSize x) = "tickSize" .= x+axisConfigProperty (TickWidth x) = "tickWidth" .= x+axisConfigProperty (Ticks b) = "ticks" .= b+axisConfigProperty NoTitle = "title" .= A.Null+axisConfigProperty (TitleAlign algn) = "titleAlign" .= hAlignLabel algn+axisConfigProperty (TitleAnchor a) = "titleAnchor" .= anchorLabel a+axisConfigProperty (TitleAngle x) = "titleAngle" .= x+axisConfigProperty (TitleBaseline va) = "titleBaseline" .= vAlignLabel va+axisConfigProperty (TitleColor c) = "titleColor" .= fromColor c+axisConfigProperty (TitleFont f) = "titleFont" .= f+axisConfigProperty (TitleFontSize x) = "titleFontSize" .= x+axisConfigProperty (TitleFontStyle s) = "titleFontStyle" .= s+axisConfigProperty (TitleFontWeight w) = "titleFontWeight" .= fontWeightSpec w+axisConfigProperty (TitleLimit x) = "titleLimit" .= x+axisConfigProperty (TitleLineHeight x) = "titleLineHeight" .= x+axisConfigProperty (TitleOpacity x) = "titleOpacity" .= x+axisConfigProperty (TitlePadding x) = "titlePadding" .= x+axisConfigProperty (TitleX x) = "titleX" .= x+axisConfigProperty (TitleY x) = "titleY" .= x+axisConfigProperty (TranslateOffset x) = "translate" .= x++{-|++Configuration options for faceted views, used with 'Graphics.Vega.VegaLite.FacetStyle'.++See the+<https://vega.github.io/vega-lite/docs/facet.html#facet-configuration Vega-Lite facet config documentation>.++@since 0.4.0.0++-}+data FacetConfig+    = FColumns Int+    -- ^ The maximum number of columns to use in a faceted-flow layout.+    | FSpacing Double+    -- ^ The spacing in pixels between sub-views in a faceted composition.+++facetConfigProperty :: FacetConfig -> LabelledSpec+facetConfigProperty (FColumns n) = "columns" .= n+facetConfigProperty (FSpacing x) = "spacing" .= x+++-- | Specifies how the title anchor is positioned relative to the frame.+--+--   @since 0.4.0.0+data TitleFrame+    = FrBounds+      -- ^ The position is relative to the full bounding box.+    | FrGroup+      -- ^ The pistion is relative to the group width / height.++titleFrameSpec :: TitleFrame -> VLSpec+titleFrameSpec FrBounds = "bounds"+titleFrameSpec FrGroup = "group"+++{-|++Title configuration properties. These are used to configure the default style+of all titles within a visualization with 'title' or 'TitleStyle'.++For further details see the+<https://vega.github.io/vega-lite/docs/title.html#config Vega-Lite documentation>.++-}++-- NOTES:+--   do not have a 'TTitle' field because this is handled by the first+--   argument of title, so there's no point in having it here (also, would+--   have to be called something different than TTitle as we already have+--   this).+--+--   could move TSubtitle out too, but the ergonomics aren't great+--   either way++data TitleConfig+    = TAlign HAlign+      -- ^ The horizontal text alignment for title text.+      --+      --   @since 0.5.0.0+    | TAnchor APosition+      -- ^ The anchor position when placing titles.+    | TAngle Angle+      -- ^ The angle when orientating titles.+    | TBaseline VAlign+      -- ^ The vertical alignment when placing titles.+    | TColor Color  -- this allows for null as a color+      -- ^ The color of title text.+    | TdX Double+      -- ^ The offset, in pixels, for the x coordinate of title and subtitle text.+      --+      --   @since 0.5.0.0+    | TdY Double+      -- ^ The offset, in pixels, for the x coordinate of title and subtitle text.+      --+      --   @since 0.5.0.0+    | TFont T.Text+      -- ^ Default font when showing titles.+    | TFontSize Double+      -- ^ Default font size when showing titles.+    | TFontStyle T.Text+      -- ^ Defaylt font style when showing titles.+      --+      --   @since 0.4.0.0+    | TFontWeight FontWeight+      -- ^ Default font weight when showing titles.+    | TFrame TitleFrame+      -- ^ Default title position anchor.+      --+      --   @since 0.4.0.0+    | TLimit Double+      -- ^ The maximum length, in pixels, of title and subtitle text.+    | TLineHeight Double+      -- ^ Line height, in pixels, for multi-line title text.+      --+      --   @since 0.5.0.0+    | TOffset Double+      -- ^ Default offset, in pixels, of titles relative to the chart body.+    | TOrient Side+      -- ^ Default placement of titles relative to the chart body.+    | TStyle [T.Text]+      -- ^ A list of named styles to apply. A named style can be specified+      --   via 'Graphics.Vega.VegaLite.NamedStyle' or 'Graphics.Vega.VegaLite.NamedStyles'. Later styles in the list will+      --   override earlier ones if there is a conflict in any of the+      --   properties.+      --+      --   @since 0.4.0.0+    | TSubtitle T.Text+      -- ^ Subtitle text. This is placed below the title text. Use \n+      --   to insert line breaks into the subtitle.+      --+      --   This should only be used with 'title' and not 'TitleConfig'.+      --+      --   @since 0.5.0.0+    | TSubtitleColor Color+      -- ^ Subtitle color.+      --+      --   @since 0.5.0.0+    | TSubtitleFont T.Text+      -- ^ Subtitle font.+      --+      --   @since 0.5.0.0+    | TSubtitleFontSize Double+      -- ^ Subtitle font size, in pixels.+      --+      --   @since 0.5.0.0+    | TSubtitleFontStyle T.Text+      -- ^ Subtitle font style.+      --+      --   @since 0.5.0.0+    | TSubtitleFontWeight FontWeight+      -- ^ Subtitle font weight.+      --+      --   @since 0.5.0.0+    | TSubtitleLineHeight Double+      -- ^ Subtitle line height, in pixels.+      --+      --   @since 0.5.0.0+    | TSubtitlePadding Double+      -- ^ Padding, in pixels, between the title and Subtitle.+      --+      --   @since 0.5.0.0+    | TZIndex ZIndex+      -- ^ Drawing order of a title relative to the other chart elements.+      --+      --   This should only be used with 'title' and not 'TitleConfig'.+      --+      --   @since 0.4.0.0+++titleConfigSpec :: TitleConfig -> LabelledSpec+titleConfigSpec (TAlign ha) = "align" .= hAlignLabel ha+titleConfigSpec (TAnchor an) = "anchor" .= anchorLabel an+titleConfigSpec (TAngle x) = "angle" .= x+titleConfigSpec (TBaseline va) = "baseline" .= vAlignLabel va+titleConfigSpec (TColor clr) = "color" .= fromColor clr+titleConfigSpec (TdX x) = "dx" .= x+titleConfigSpec (TdY x) = "dy" .= x+titleConfigSpec (TFont fnt) = "font" .= fnt+titleConfigSpec (TFontSize x) = "fontSize" .= x+titleConfigSpec (TFontStyle s) = "fontStyle" .= s+titleConfigSpec (TFontWeight w) = "fontWeight" .= fontWeightSpec w+titleConfigSpec (TFrame tf) = "frame" .= titleFrameSpec tf+titleConfigSpec (TLimit x) = "limit" .= x+titleConfigSpec (TLineHeight x) = "lineHeight" .= x+titleConfigSpec (TOffset x) = "offset" .= x+titleConfigSpec (TOrient sd) = "orient" .= sideLabel sd+titleConfigSpec (TStyle [style]) = "style" .= style  -- not really needed+titleConfigSpec (TStyle styles) = "style" .= styles+titleConfigSpec (TSubtitle s) = "subtitle" .= splitOnNewline s+titleConfigSpec (TSubtitleColor s) = "subtitleColor" .= fromColor s+titleConfigSpec (TSubtitleFont s) = "subtitleFont" .= s+titleConfigSpec (TSubtitleFontSize x) = "subtitleFontSize" .= x+titleConfigSpec (TSubtitleFontStyle s) = "subtitleFontStyle" .= s+titleConfigSpec (TSubtitleFontWeight fw) = "subtitleFontWeight" .= fontWeightSpec fw+titleConfigSpec (TSubtitleLineHeight x) = "subtitleLineHeight" .= x+titleConfigSpec (TSubtitlePadding x) = "subtitlePadding" .= x+titleConfigSpec (TZIndex z) = "zindex" .= z+++{-|++Configuration options for concatenated views, used with 'Graphics.Vega.VegaLite.ConcatStyle'.++@since 0.4.0.0++-}+data ConcatConfig+    = ConcatColumns Int+      -- ^ The maximum number of columns to use in a concatenated flow layout.+    | ConcatSpacing Double+      -- ^ The spacing in pixels between sub-views in a concatenated view.+++concatConfigProperty :: ConcatConfig -> LabelledSpec+concatConfigProperty (ConcatColumns n) = "columns" .= n+concatConfigProperty (ConcatSpacing x) = "spacing" .= x+++{-|++Defines a single configuration option to be applied globally across the visualization.+The first parameter identifies the type of configuration, the second a list of previous+configurations to which this one may be added.++The result should be used with 'Graphics.Vega.VegaLite.configure'.++@+'configuration' ('Axis' [ 'DomainWidth' 4 ]) []+@+-}+configuration ::+  ConfigurationProperty+  -> BuildConfigureSpecs+  -- ^ Prior to version @0.5.0.0@ this was @BuildLabelledSpecs@.+configuration cfg ols = CS (configProperty cfg) : ols+++{-|++Provide an optional title to be displayed in the visualization.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'title' "Population Growth" ['TColor' \"orange\"]+    , 'Graphics.Vega.VegaLite.dataFromUrl' \"data/population.json\" []+    , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Bar' []+    , 'Graphics.Vega.VegaLite.encoding' ...+    ]+@++Prior to @0.4.0.0@ there was no way to set the title options+(other than using 'configuration' with 'TitleStyle').++-}+title ::+  T.Text+  -- ^ The title. Any @'\n'@ characters are taken to mean a multi-line+  --   string and indicate a line break.+  --+  --   In version @0.5.0.0@, support for line breaks was added.+  -> [TitleConfig]+  -- ^ Configure the appearance of the title.+  --+  --   @since 0.4.0.0+  -> PropertySpec+title s [] =+  (VLTitle, splitOnNewline s)+title s topts =+  (VLTitle,+    object ("text" .= splitOnNewline s : map titleConfigSpec topts))
+ src/Graphics/Vega/VegaLite/Core.hs view
@@ -0,0 +1,4546 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}++{-|+Module      : Graphics.Vega.VegaLite.Core+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings++The main fuctionality of VegaLite is provided by+the Foundation and Core modules, but there are types+(and functions) scattered around the place. There is+some logic into what goes where, but it's not perfect.++-}++module Graphics.Vega.VegaLite.Core+       ( transform++       , aggregate+       , joinAggregate+       , opAs+       , timeUnitAs++       , binAs++       , stack++       , calculateAs++       , filter+       , Filter(..)+       , FilterRange(..)++       , flatten+       , flattenAs+       , fold+       , foldAs+       , pivot+       , PivotProperty(..)++       , lookup+       , lookupSelection+       , LookupFields(..)+       , lookupAs++       , impute++       , sample++       , density+       , DensityProperty(..)++       , loess+       , LoessProperty(..)++       , regression+       , RegressionProperty(..)+       , RegressionMethod(..)++       , quantile+       , QuantileProperty(..)++       , window++       , mark++       , encoding++       , position++       , PositionChannel(..)++       , SortProperty(..)++       , AxisProperty(..)+       , ConditionalAxisProperty(..)++       , size+       , color+       , fill+       , stroke+       , strokeWidth+       , opacity+       , fillOpacity+       , strokeOpacity+       , shape++       , MarkChannel(..)++       , text+       , tooltip+       , tooltips+       , TextChannel(..)++       , hyperlink+       , HyperlinkChannel(..)++       , url++       , order+       , OrderChannel(..)++       , row+       , column++       , detail+       , DetailChannel(..)++       , ScaleProperty(..)+       , categoricalDomainMap+       , domainRangeMap++       , layer+       , vlConcat+       , columns+       , hConcat+       , vConcat+       , align+       , alignRC+       , spacing+       , spacingRC+       , center+       , centerRC+       , bounds++       , resolve+       , resolution++       , repeat+       , repeatFlow+       , facet+       , facetFlow+       , FacetMapping(..)+       , FacetChannel(..)++       , BooleanOp(..)++       , name+       , description+       , height+       , heightOfContainer+       , heightStep+       , width+       , widthOfContainer+       , widthStep+       , padding+       , autosize+       , background+       , usermetadata++       , viewBackground++       , configure++       -- not for external export+       , schemeProperty+       , autosizeProperty+       , paddingSpec++       )+    where++-- VegaLite uses these symbols.+import Prelude hiding (filter, lookup, repeat)++import qualified Data.Aeson as A+import qualified Data.Text as T++import Data.Aeson (object, toJSON, (.=))+import Data.Maybe (mapMaybe)++#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)++import Graphics.Vega.VegaLite.Data+  ( DataValue(..)+  , DataValues(..)+  , dataValueSpec+  , dataValuesSpecs+  )+import Graphics.Vega.VegaLite.Foundation+  ( Angle+  , Color+  , DashStyle+  , DashOffset+  , FieldName+  , Opacity+  , VegaExpr+  , ZIndex+  , FontWeight+  , Measurement+  , Arrangement+  , APosition+  , Position+  , HAlign+  , VAlign+  , BandAlign+  , Scale+  , OverlapStrategy+  , Side+  , StackProperty+  , StackOffset+  , Channel+  , Resolve+  , Bounds+  , CompositionAlignment+  , Padding+  , Autosize+  , RepeatFields+  , CInterpolate+  , ViewBackground+  , HeaderProperty+  , fromT+  , fromColor+  , fromDS+  , splitOnNewline+  , field_+  , header_+  , order_+  , fontWeightSpec+  , measurementLabel+  , arrangementLabel+  , anchorLabel+  , hAlignLabel+  , vAlignLabel+  , bandAlignLabel+  , scaleLabel+  , positionLabel+  , overlapStrategyLabel+  , sideLabel+  , stackPropertySpecSort+  , stackPropertySpecOffset+  , stackOffset+  , channelLabel+  , resolveProperty+  , boundsSpec+  , compositionAlignmentSpec+  , paddingSpec+  , autosizeProperty+  , repeatFieldsProperty+  , cInterpolateSpec+  , viewBackgroundSpec+  )+import Graphics.Vega.VegaLite.Input+  ( Data+  )+import Graphics.Vega.VegaLite.Legend+  ( LegendProperty+  , legendProp_+  )+import Graphics.Vega.VegaLite.Mark+  ( Mark+  , MarkProperty+  , markLabel+  , markProperty+  )+import Graphics.Vega.VegaLite.Scale+  ( ScaleDomain(..)+  , ScaleRange(..)+  , ScaleNice+  , scaleDomainSpec+  , scaleNiceSpec+  )+import Graphics.Vega.VegaLite.Specification+  ( VLProperty(..)+  , VLSpec+  , PropertySpec+  , LabelledSpec+  , EncodingSpec(..)+  , BuildEncodingSpecs+  , TransformSpec(..)+  , BuildTransformSpecs+  , ConfigureSpec(..)+  , ResolveSpec(..)+  , BuildResolveSpecs+  , SelectionLabel+  )+import Graphics.Vega.VegaLite.Time+  ( DateTime+  , TimeUnit+  , timeUnit_+  , dateTimeProperty+  , timeUnitLabel+  )+import Graphics.Vega.VegaLite.Transform+  ( Operation(Count)+  , Window+  , BinProperty+  , WindowProperty+  , ImputeProperty+  , aggregate_+  , op_+  , binned_+  , impute_+  , bin+  , binProperty+  , operationSpec+  , windowTS+  , joinAggregateTS+  , imputeTS+  )++--- helpers++-- This could be extended to any Ord type but specialize for now to Double+clamped ::+  Double+  -- ^ minimum value allowed+  -> Double+  -- ^ maximum value allowed (must be > the minimum value)+  -> Double+  -- ^ user value+  -> Double+clamped xmin xmax x = max xmin (min xmax x)+++repeat_ :: Arrangement -> LabelledSpec+repeat_ arr = "repeat" .= arrangementLabel arr++sort_ :: [SortProperty] -> LabelledSpec+sort_ ops = "sort" .= sortPropertySpec ops++mchan_ :: T.Text -> [MarkChannel] -> EncodingSpec+mchan_ f ms = ES (f .= object (concatMap markChannelProperty ms))++mtype_ :: Measurement -> LabelledSpec+mtype_ m = "type" .= measurementLabel m++-- The assumption at the moment is that it's always correct to+-- replace the empty list by null.+--+scaleProp_ :: [ScaleProperty] -> LabelledSpec+scaleProp_ [] = "scale" .= A.Null+scaleProp_ sps = "scale" .= object (map scaleProperty sps)+++value_ :: T.Text -> LabelledSpec+value_ v = "value" .= v+++selCond_ :: (a -> [LabelledSpec]) -> BooleanOp -> [a] -> [a] -> [LabelledSpec]+selCond_ getProps selName ifClause elseClause =+  let h = ("condition", hkey)+      toProps = concatMap getProps+      hkey = object (("selection", booleanOpSpec selName) : toProps ifClause)+      hs = toProps elseClause+  in h : hs++-- Special case the single-condition check, so that I don't get false+-- positives when comparing against the Vega-Lite specification. There+-- should be no actionable difference from this special case (i.e.+-- the output being '[object]' and 'object' have the same meaning).+--+-- There is also the simplification to replace+--      test: { selection: xxx }+-- by+--      selection: xxx+-- which happens for the Selection operator.+--+dataCond_ :: (a -> [LabelledSpec]) -> [(BooleanOp, [a])] -> [a] -> [LabelledSpec]+dataCond_ getProps tests elseClause =+  let h = ("condition", condClause)+      condClause = case conds of+                     [cond] -> cond+                     _ -> toJSON conds+      conds = map testClause tests+      testClause (Selection sel, ifClause) =+        object (("selection" .= sel) : toProps ifClause)+      testClause (predicate, ifClause) =+        object (("test", booleanOpSpec predicate) : toProps ifClause)+      toProps = concatMap getProps+      hs = toProps elseClause+  in h : hs++++{-|++Create a named aggregation operation on a field that can be added to a transformation.+For further details see the+<https://vega.github.io/vega-lite/docs/aggregate.html#aggregate-op-def Vega-Lite documentation>.++@+'transform'+    . 'aggregate'+        [ 'opAs' 'Graphics.Vega.VegaLite.Min' "people" "lowerBound"+        , 'opAs' 'Graphics.Vega.VegaLite.Max' "people" "upperBound"+        ]+        [ "age" ]+@+-}+opAs ::+  Operation+  -- ^ The aggregation operation to use.+  -> FieldName+  -- ^ The name of the field which is to be aggregated (when the operation+  --   is 'Count' leave as the empty string).+  -> FieldName+  -- ^ The name given to the transformed data.+  -> VLSpec++-- The Count case is special-cased purely to make it easier to compare+-- the hvega output against the Veg-Lite examples. There should be no+-- semantic difference here.+--+opAs Count _ label =+  object [ op_ Count, "as" .= label ]+opAs op field label =+  object [ op_ op, field_ field, "as" .= label ]+++{-|++Create a mark specification. All marks must have a type (first parameter) and+can optionally be customised with a list of mark properties such as interpolation+style for lines. To keep the default style for the mark, just provide an empty list+for the second parameter.++@+'mark' 'Graphics.Vega.VegaLite.Circle' []+'mark' 'Graphics.Vega.VegaLite.Line' ['Graphics.Vega.VegaLite.MInterpolate' 'Graphics.Vega.VegaLite.StepAfter']+@++@+let dvals = 'Graphics.Vega.VegaLite.dataFromUrl' \"city.json\" ['Graphics.Vega.VegaLite.TopojsonFeature' \"boroughs\"] []+    markOpts = 'mark' 'Graphics.Vega.VegaLite.Geoshape' ['Graphics.Vega.VegaLite.MFill' \"lightgrey\", 'Graphics.Vega.VegaLite.MStroke' \"white\"]+in 'Graphics.Vega.VegaLite.toVegaLite' [dvals, markOpts]+@+-}+mark :: Mark -> [MarkProperty] -> PropertySpec+mark mrk props =+  let jsName = toJSON (markLabel mrk)+      vals = if null props+             then jsName+             else object (("type" .= jsName) : map markProperty props)++  in (VLMark, vals)+++{-|++Mark channel properties used for creating a mark channel encoding.+-}++-- https://vega.github.io/vega-lite/docs/encoding.html#mark-prop++data MarkChannel+    = MName FieldName+      -- ^ Field used for encoding with a mark property channel.+    | MRepeat Arrangement+      -- ^ Reference in a mark channel to a field name generated by 'repeatFlow'+      --   or 'repeat'. The parameter identifies whether reference is being made to+      --   fields that are to be arranged in columns, in rows, or a with a flow layout.+    | MmType Measurement+      -- ^ Level of measurement when encoding with a mark property channel.+    | MScale [ScaleProperty]+      -- ^ Scaling applied to a field when encoding with a mark property channel.+      --   The scale will transform a field's value into a color, shape, size etc.+      --+      --   Use an empty list to remove the scale.+    | MBin [BinProperty]+      -- ^ Discretize numeric values into bins when encoding with a mark property channel.+    | MBinned+      -- ^ Indicate that data encoding with a mark are already binned.+      --+      --   @since 0.4.0.0+    | MSort [SortProperty]+      -- ^ Sort order.+      --+      --   @since 0.4.0.0+    | MTimeUnit TimeUnit+      -- ^ Time unit aggregation of field values when encoding with a mark property channel.+    | MTitle T.Text+      -- ^ Title of a field when encoding with a mark property channel.+      --+      --   @since 0.4.0.0+    | MNoTitle+      -- ^ Draw no title.+      --+      --   @since 0.4.0.0+    | MAggregate Operation+      -- ^ Compute aggregate summary statistics for a field to be encoded with a+      --   mark property channel.+    | MLegend [LegendProperty]+      -- ^ Properties of a legend that describes a mark's encoding.+      --+      --   For no legend, provide an empty list.+    | MSelectionCondition BooleanOp [MarkChannel] [MarkChannel]+      -- ^ Make a mark channel conditional on interactive selection. The first parameter+      --   is a selection condition to evaluate; the second the encoding to apply if that+      --   selection is true; the third parameter is the encoding if the selection is false.+      --+      -- @+      -- 'color'+      --   [ MSelectionCondition ('SelectionName' \"myBrush\")+      --      [ 'MName' \"myField\", 'MmType' 'Graphics.Vega.VegaLite.Ordinal' ]+      --      [ 'MString' \"grey\" ]+      --   ]+      -- @+    | MDataCondition [(BooleanOp, [MarkChannel])] [MarkChannel]+      -- ^ Make a text channel conditional on one or more predicate expressions. The first+      --   parameter is a list of tuples each pairing an expression to evaluate with the encoding+      --   if that expression is @True@. The second is the encoding if none of the expressions+      --   evaluate as @True@.+      --+      -- @+      -- 'color'+      --   [ MDataCondition [ ( 'Expr' \"datum.myField === null\", [ 'MString' \"grey\" ] ) ]+      --      [ MString \"black\" ]+      --   ]+      -- @+      --+      --   The arguments to this constructor have changed in @0.4.0.0@+      --   to support multiple expressions.+    | MPath T.Text+      -- ^ SVG path string used when encoding with a mark property channel. Useful+      --   for providing custom shapes.+    | MNumber Double+      -- ^ Literal numeric value when encoding with a mark property channel.+    | MString T.Text+      -- ^ Literal string value when encoding with a mark property channel.+    | MBoolean Bool+      -- ^ Boolean value when encoding with a mark property channel.++markChannelProperty :: MarkChannel -> [LabelledSpec]+markChannelProperty (MName s) = [field_ s]+markChannelProperty (MRepeat arr) = ["field" .= object [repeat_ arr]]+markChannelProperty (MmType t) = [mtype_ t]+markChannelProperty (MScale sps) = [scaleProp_ sps]+markChannelProperty (MLegend lps) = [legendProp_ lps]+markChannelProperty (MBin bps) = [bin bps]+markChannelProperty MBinned = [binned_]+markChannelProperty (MSort ops) = [sort_ ops]+markChannelProperty (MSelectionCondition selName ifClause elseClause) =+  selCond_ markChannelProperty selName ifClause elseClause+markChannelProperty (MDataCondition tests elseClause) =+  dataCond_ markChannelProperty tests elseClause+markChannelProperty (MTimeUnit tu) = [timeUnit_ tu]+markChannelProperty (MAggregate op) = [aggregate_ op]+markChannelProperty (MPath s) = ["value" .= s]+markChannelProperty (MNumber x) = ["value" .= x]+markChannelProperty (MString s) = ["value" .= s]+markChannelProperty (MBoolean b) = ["value" .= b]+markChannelProperty (MTitle s) = ["title" .= splitOnNewline s]+markChannelProperty MNoTitle = ["title" .= A.Null]+++{-|++Create an encoding specification from a list of channel encodings.++@+enc = 'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"Animal\", 'PmType' 'Graphics.Vega.VegaLite.Ordinal' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"Age\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'shape' [ 'MName' \"Species\", 'MmType' 'Graphics.Vega.VegaLite.Nominal' ]+        . 'size' [ 'MName' \"Population\", 'MmType' 'Graphics.Vega.VegaLite.Quantitative' ]+@++The type of @enc@ in this example is @[EncodingSpec] -> PropertySpec@,+so it can either be used to add further encoding specifications or as+@enc []@ to create a specification.++The supported encodings are:+'color', 'column', 'detail', 'fill', 'fillOpacity', 'hyperlink',+'opacity', 'order', 'position', 'row', 'shape', 'size',+'stroke', 'strokeOpacity', 'strokeWidth', 'text', 'tooltip',+'tooltips', and 'url'.++There is currently no support for encoding by+<https://vega.github.io/vega-lite/docs/encoding.html#key key>.++-}+encoding ::+  [EncodingSpec]+  -- ^ The channel encodings (the order does not matter).+  --+  --   Prior to @0.5.0.0@ this argument was @['LabelledSpec']@.+  -> PropertySpec+encoding channels = (VLEncoding, object (map unES channels))+++{-|++Apply a stack transform for positioning multiple values. This is an alternative+to specifying stacking directly when encoding position.++@+'transform'+    . 'aggregate' [ 'opAs' 'Count' \"\" \"count_*\" ] [ \"Origin\", \"Cylinders\" ]+    . 'stack' "count_*"+        []+        \"stack_count_Origin1\"+        \"stack_count_Origin2\"+        [ 'Graphics.Vega.VegaLite.StOffset' 'Graphics.Vega.VegaLite.StNormalize', 'Graphics.Vega.VegaLite.StSort' [ 'Graphics.Vega.VegaLite.WAscending' \"Origin\" ] ]+    . 'window'+        [ ( [ 'Graphics.Vega.VegaLite.WAggregateOp' 'Graphics.Vega.VegaLite.Min', 'Graphics.Vega.VegaLite.WField' \"stack_count_Origin1\" ], \"x\" )+        , ( [ 'Graphics.Vega.VegaLite.WAggregateOp' 'Graphics.Vega.VegaLite.Max', 'Graphics.Vega.VegaLite.WField' \"stack_count_Origin2\" ], \"x2\" )+        ]+        [ 'Graphics.Vega.VegaLite.WFrame' Nothing Nothing, 'Graphics.Vega.VegaLite.WGroupBy' [ \"Origin\" ] ]+    . 'stack' \"count_*\"+        [ \"Origin\" ]+        \"y\"+        \"y2\"+        [ 'Graphics.Vega.VegaLite.StOffset' 'Graphics.Vega.VegaLite.StNormalize', 'Graphics.Vega.VegaLite.StSort' [ 'Graphics.Vega.VegaLite.WAscending' \"Cylinders\" ] ]+@++@since 0.4.0.0++-}++stack ::+  FieldName+  -- ^ The field to be stacked.+  -> [FieldName]+  -- ^ The fields to group by.+  -> FieldName+  -- ^ The output field name (start).+  -> FieldName+  -- ^ The output field name (end).+  -> [StackProperty]+  -- ^ Offset and sort properties.+  -> BuildTransformSpecs+stack f grp start end sProps ols =+  let addField n [x] = [n .= x]+      addField _ _ = []++      mOffset = mapMaybe stackPropertySpecOffset sProps+      mSort = mapMaybe stackPropertySpecSort sProps++      fields = [ "stack" .= f+               , "groupby" .= grp+               , "as" .= [ start, end ] ]+               <> addField "offset" mOffset+               <> addField "sort" mSort++  in TS (object fields) : ols+++{-|++Individual scale property. These are used to customise an individual scale+transformation. To customise all scales use 'configure' and supply relevant+'Graphics.Vega.VegaLite.ScaleConfig' values. For more details see the+<https://vega.github.io/vega-lite/docs/scale.html Vega-Lite documentation>.++There are two utility routines for constructing a list of scale+properties: 'categoricalDomainMap' and 'domainRangeMap'.++The @SRangeStep@ constructor was removed in version @0.5.0.0@. Users+should use the 'heightStep' and 'widthStep' functions instead.++The @SReverse@ constructor was removed in version @0.4.0.0@, as it+represented a Vega, rather than Vega-Lite, property. The order of+a scale can be changed with the 'PSort' constructor.+-}++-- based on schema 3.3.0 #/definitions/Scale++data ScaleProperty+    = SType Scale+      -- ^ Type of scaling to apply.+    | SAlign Double+      -- ^ Alignment of the steps within the scale range. A value of+      --   @0@ shifts the bands to an axis, @1@ away from the axis,+      --   and @0.5@ is centered within the range.+      --+      --   The input is clamped so that values less than 0 are mapped+      --   to 0 and greater than 1 to 1.+      --+      --   @since 0.4.0.0+    | SBase Double+      -- ^ The base to use for log scaling ('Graphics.Vega.VegaLite.ScLog').+      --+      --   Default is @10@.+      --+      --   @since 0.4.0.0+    | SBins [Double]+      -- ^ An array of bin boundaries over the scale domain. If give, axes and legends will use+      --   these boundaries to inform the choice of tick marks and text labels.+      --+      --   @since 0.4.0.0+    | SClamp Bool+      -- ^ Should values outside the data domain be clamped (to the minimum or+      --   maximum value)?+    | SConstant Double+      -- ^ The desired slope of the 'Graphics.Vega.VegaLite.ScSymLog' function at zero.+      --+      --   The default is @1@.+      --+      --   @since 0.4.0.0+    | SDomain ScaleDomain+      -- ^ Custom scaling domain.+    | SExponent Double+      -- ^ The exponent to use for power scaling ('Graphics.Vega.VegaLite.ScPow').+      --+      --   @since 0.4.0.0+    | SInterpolate CInterpolate+      -- ^ Interpolation method for scaling range values.+    | SNice ScaleNice+      -- ^ \"Nice\" minimum and maximum values in a scaling (e.g. multiples of 10).+    | SPadding Double+      -- ^ Padding in pixels to apply to a scaling.+    | SPaddingInner Double+      -- ^ Inner padding to apply to a band scaling.+    | SPaddingOuter Double+      -- ^ Outer padding to apply to a band scaling.+    | SRange ScaleRange+      -- ^ Range of a scaling. The type of range depends on the encoding channel.+    | SRound Bool+      -- ^ Are numeric values in a scaling are rounded to integers?+      --+      --   The default is @False@.+    | SScheme T.Text [Double]+      -- ^  Color scheme used by a color scaling. The first parameter is the+      --    name of the scheme (e.g. \"viridis\") and the second an optional+      --    specification, which can contain 1, 2, or 3 numbers:+      --+      --      - the number of colors to use (list of one number);+      --      - the extent of the color range to use (list of two numbers between 0 and 1);+      --      - the number of colors and extent (three numbers, first is the number of colors).+      --+      --    The number of colors was broken prior to @0.4.0.0@ and the option to+      --    define both the count and extent was added in @0.4.0.0@.+    | SZero Bool+      -- ^ Should a numeric scaling be forced to include a zero value?+      --+      --   Not all scales support @SZero@ and the default depends on the type of+      --   channel.++scaleProperty :: ScaleProperty -> LabelledSpec+scaleProperty (SType sType) = "type" .= scaleLabel sType+scaleProperty (SAlign c) = "align" .= clamped 0 1 c+scaleProperty (SBase x) = "base" .= x+scaleProperty (SBins xs) = "bins" .= xs+scaleProperty (SClamp b) = "clamp" .= b+scaleProperty (SConstant x) = "constant" .= x+scaleProperty (SDomain sdType) = "domain" .= scaleDomainSpec sdType+scaleProperty (SExponent x) = "exponent" .= x+scaleProperty (SInterpolate interp) = "interpolate" .= cInterpolateSpec interp+scaleProperty (SNice ni) = "nice" .= scaleNiceSpec ni+scaleProperty (SPadding x) = "padding" .= x+scaleProperty (SPaddingInner x) = "paddingInner" .= x+scaleProperty (SPaddingOuter x) = "paddingOuter" .= x+scaleProperty (SRange (RNumbers xs)) = "range" .= xs+scaleProperty (SRange (RStrings ss)) = "range" .= ss+scaleProperty (SRange (RName s)) = "range" .= s+scaleProperty (SRound b) = "round" .= b+scaleProperty (SScheme nme extent) = schemeProperty nme extent+scaleProperty (SZero b) = "zero" .= b+++-- TODO: there should probably be a more-structured way to specify this+--+-- based on schema 3.3.0 #/definitions/SchemeParams++schemeProperty :: T.Text -> [Double] -> LabelledSpec+schemeProperty nme [n] = "scheme" .= object ["name" .= nme, "count" .= n]+schemeProperty nme [mn, mx] = "scheme" .= object ["name" .= nme, "extent" .= [mn, mx]]+schemeProperty nme [n, mn, mx] = "scheme" .= object ["name" .= nme, "count" .= n, "extent" .= [mn, mx]]+schemeProperty nme _ = "scheme" .= nme+++{-|++Allow type of sorting to be customised. For details see the+<https://vega.github.io/vega-lite/docs/sort.html Vega-Lite documentation>.++The constructors have been changed in version @0.4.0.0@, with+@Op@, @ByField@, and @ByRepeat@ removed, and their functionality+replaced with 'ByRepeatOp', 'ByFieldOp', and 'ByChannel'.++-}+data SortProperty+    = Ascending+      -- ^ Sorting is from low to high.+    | Descending+      -- ^ Sorting is from high to low.+    | CustomSort DataValues+      -- ^ Custom sort order listing data values explicitly.+      --+      --   @since 0.4.0.0+    | ByRepeatOp Arrangement Operation+      -- ^ Sort by the aggregated summaries of the given fields+      --   (referenced by a repeat iterator) using an aggregation+      --   operation.+      --+      --   @since 0.4.0.0+    | ByFieldOp FieldName Operation+      -- ^ Sort by the aggregated summary of a field using an aggregation+      --   operation. The following example sorts the categorical data field+      --   @variety@ by the mean age of the data in each variety category:+      --+      -- @+      -- 'position' 'Graphics.Vega.VegaLite.Y'+      --   [ 'PName' "variety"+      --   , 'PmType' 'Graphics.Vega.VegaLite.Ordinal'+      --   , 'PSort' [ ByFieldOp "age" 'Graphics.Vega.VegaLite.Mean', 'Descending' ]+      --   ]+      -- @+      --+      --   @since 0.4.0.0+    | ByChannel Channel+      -- ^ Sort by another channel.+      --+      -- @+      -- 'position' 'Graphics.Vega.VegaLite.Y'+      --  [ 'PName' "age"+      --  , 'PmType' 'Graphics.Vega.VegaLite.Ordinal'+      --  , 'PSort' [ ByChannel 'Graphics.Vega.VegaLite.ChX' ]+      --  ]+      -- @+      --+      --   @since 0.4.0.0+++sortProperty :: SortProperty -> [LabelledSpec]+sortProperty Ascending = [order_ "ascending"]+sortProperty Descending = [order_ "descending"]+sortProperty (ByChannel ch) = ["encoding" .= channelLabel ch]+sortProperty (ByFieldOp field op) = [field_ field, op_ op]+sortProperty (ByRepeatOp arr op) = ["field" .= object [repeat_ arr], op_ op]+sortProperty (CustomSort _) = []+++sortPropertySpec :: [SortProperty] -> VLSpec+sortPropertySpec [] = A.Null+sortPropertySpec [Ascending] = fromT "ascending"+sortPropertySpec [Descending] = fromT "descending"+sortPropertySpec [CustomSort dvs] = toJSON (dataValuesSpecs dvs)+sortPropertySpec sps = object (concatMap sortProperty sps)+++-- | Position channel properties used for creating a position channel encoding.++data PositionChannel+    = PName FieldName+      -- ^ Name of the field used for encoding with a position channel.+    | PHeight+      -- ^ Set the position to the height of the enclosing data space. Useful for placing+      --   a mark relative to the bottom edge of a view.+      --+      --   @since 0.4.0.0+    | PWidth+      -- ^ Set the position to the width of the enclosing data space. Useful for justifying+      --   a mark to the right hand edge of a view. e.g. to position a mark at the right of+      --   the data rectangle:+      --+      -- @+      -- enc =+      --   'encoding'+      --      . 'position' 'Graphics.Vega.VegaLite.X' [ PWidth ]+      -- @+      --+      --   @since 0.4.0.0+    | PNumber Double+      -- ^ Set a position to an arbitrary value. Useful for placing items at the top of+      --   a plot area (@PNumber 0@) or a fixed number of pixels from the top.+      --   See also 'PHeight' and 'PWidth'.+      --+      --   @since 0.4.0.0+    | PRepeat Arrangement+      -- ^ Reference in a position channel to a field name generated by 'repeatFlow'+      --   or 'repeat'. The parameter identifies whether reference is being made to+      --   fields that are to be arranged in columns, in rows, or a with a flow layout.+      --+      --   For example:+      --+      -- @+      -- enc =+      --   'encoding'+      --      . 'position' 'Graphics.Vega.VegaLite.X' [ PRepeat 'Graphics.Vega.VegaLite.Flow', 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+      --+      -- spec =+      --    'Graphics.Vega.VegaLite.asSpec' [ dataVals [], 'mark' 'Graphics.Vega.VegaLite.Tick' [], enc [] ]+      --+      -- 'Graphics.Vega.VegaLite.toVegaLite'+      --    [ 'repeatFlow' [ \"Horsepower\", \"Miles_per_Gallon\", \"Acceleration\"]+      --    , 'Graphics.Vega.VegaLite.specification' spec+      --    ]+      -- @+    | PmType Measurement+      -- ^ Level of measurement when encoding with a position channel.+    | PBin [BinProperty]+      -- ^ Discretize numeric values into bins when encoding with a+      --   position channel.+      --+      --   For example, to encode a frequency histogram with bins every 5 units:+      --+      --   @+      --   enc = 'encoding'+      --           . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"x\"+      --                        , 'PmType' 'Graphics.Vega.VegaLite.Ordinal'+      --                        , 'PBin' ['Graphics.Vega.VegaLite.Step' 5]+      --                        ]+      --           . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PmType' 'Graphics.Vega.VegaLite.Quantitative'+      --                        , 'PAggregate' 'Count'+      --                        ]+      --   @+    | PBinned+      -- ^ Indicate that the data encoded with position is already binned.+      --+      --   @since 0.4.0.0+    | PTimeUnit TimeUnit+      -- ^ Form of time unit aggregation of field values when encoding with a position channel.+    | PTitle T.Text+      -- ^ Title of a field when encoding with a position channel.+      --+      --   @since 0.4.0.0+    | PNoTitle+      -- ^ Draw no title.+      --+      -- @since 0.4.0.0+    | PAggregate Operation+      -- ^ Compute some aggregate summary statistics for a field to be encoded+      --   with a position channel.+      --+      --   @+      --   enc = 'encoding'+      --           . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"role\", 'PmType' 'Graphics.Vega.VegaLite.Ordinal' ]+      --           . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"salary\"+      --                        , 'PmType' 'Graphics.Vega.VegaLite.Quantitative'+      --                        , 'PAggregate' 'Graphics.Vega.VegaLite.Mean'+      --                        ]+      --   @+    | PScale [ScaleProperty]+      -- ^ Scaling applied to a field when encoding with a position channel.+      --   The scale will transform a field's value into a position along+      --   one axis.+      --+      --   For example, the following will scale the bars positioned along+      --   a horizontal axis to have an inner spacing of 50% (0.5) of the+      --   total space allocated to each bar:+      --+      --   @+      --   enc = 'encoding'+      --           . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"ageGroup\"+      --                        , 'PmType' 'Graphics.Vega.VegaLite.Nominal'+      --                        , 'PScale' ['SPaddingInner' 0.5]+      --                        ]+      --   @+    | PAxis [AxisProperty]+      -- ^ Axis properties used when encoding with a position channel. For no axis,+      --   provide an empty list.+    | PSort [SortProperty]+      -- ^ Sort order for field when encoding with a position channel.+    | PStack StackOffset+      -- ^ Type of stacking offset for the field when encoding with a+      --   position channel.+      --+      --   For example, stacking areas away from a centreline can be used+      --   to create a+      --   [streamgraph](https://vega.github.io/vega-lite/examples/stacked_area_stream.html):+      --+      --   @+      --   enc = 'encoding'+      --           . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"week\", 'PmType' 'Graphics.Vega.VegaLite.Ordinal']+      --           . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"takings\"+      --                        , 'PmType' 'Graphics.Vega.VegaLite.Quantitative'+      --                        , 'PStack' 'Graphics.Vega.VegaLite.StCenter'+      --                        ]+      --           . 'color' ['MName' \"shop\", 'MmType' 'Graphics.Vega.VegaLite.Nominal']+      --   @+      --+      --   Changed from @StackProperty@ in version @0.4.0.0@.+    | PImpute [ImputeProperty]+      -- ^ Set the imputation rules for a position channel. See the+      --   [Vega-Lite impute documentation](https://vega.github.io/vega-lite/docs/impute.html).+      --+      --   @since 0.4.0.0+    | PBand Double+      -- ^ Specify the mark position or size relative to the band size.+      --   The value is in the range 0 to 1, inclusive.+      --+      --   For rectangular-based marks ('Graphics.Vega.VegaLite.Rect', 'Graphics.Vega.VegaLite.Bar', and 'Graphics.Vega.VegaLite.Image'),+      --   the value is the scale factor relative to the band width+      --   (or height), or the time unit interval.+      --+      --   For non-rectangular marks, the relative position on a band of a+      --   stacked, binned, time unit, or band scale is used. A value of+      --   0 positions the band at the beginning of the band, and 1+      --   at the end.+      --+      --   @since 0.5.0.0++positionChannelProperty :: PositionChannel -> LabelledSpec+positionChannelProperty (PName s) = field_ s+positionChannelProperty (PmType m) = mtype_ m+positionChannelProperty (PBin b) = bin b+positionChannelProperty PBinned = binned_+positionChannelProperty (PAggregate op) = aggregate_ op+positionChannelProperty (PTimeUnit tu) = timeUnit_ tu+positionChannelProperty (PTitle s) = "title" .= splitOnNewline s+positionChannelProperty PNoTitle = "title" .= A.Null+positionChannelProperty (PSort ops) = sort_ ops+positionChannelProperty (PScale sps) = scaleProp_ sps+positionChannelProperty (PAxis aps) =+  let js = if null aps+           then A.Null+           else object (map axisProperty aps)+  in "axis" .= js+positionChannelProperty (PStack so) = stackOffset so+positionChannelProperty (PRepeat arr) = "field" .= object [repeat_ arr]+positionChannelProperty PHeight = value_ "height"+positionChannelProperty PWidth = value_ "width"+positionChannelProperty (PNumber x) = "value" .= x+positionChannelProperty (PImpute ips) = impute_ ips+positionChannelProperty (PBand x) = "band" .= x+++{-|++Set the background color of the visualization. If not specified the background+will be white.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'background' "rgb(251,247,238)"+    , 'Graphics.Vega.VegaLite.dataFromUrl' "data/population.json" []+    , 'mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+background ::+  Color+  -- ^ The background color. For example, @\"rgba(0,0,0,0)\"@ is+  --   transparent.+  --+  --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+  -> PropertySpec+background colour = (VLBackground, fromColor colour)+++{-|++Provides an optional description to be associated with the visualization.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'description' "Population change of key regions since 1900"+    , 'Graphics.Vega.VegaLite.dataFromUrl' "data/population.json" []+    , 'mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+description :: T.Text -> PropertySpec+description s = (VLDescription, toJSON s)+++-- | Optional metadata.+--+--   @since 0.4.0.0++usermetadata ::+  A.Object+  -- ^ The metadata is passed around but ignored by VegaLite.+  -> PropertySpec+usermetadata o = (VLUserMetadata, A.Object o)+++{-|++Axis customisation properties. These are used for customising individual axes.+To configure all axes, use 'Graphics.Vega.VegaLite.AxisConfig' with a 'Graphics.Vega.VegaLite.configuration' instead. See the+<https://vega.github.io/vega-lite/docs/axis.html#axis-properties Vega-Lite documentation>+for more details.++The @AxTitleMaxLength@ constructor was removed in release @0.4.0.0@. The+'AxTitleLimit' constructor should be used instead.++-}+{-# DEPRECATED AxDates "Please change AxDates to AxValues" #-}+data AxisProperty+    = AxBandPosition Double+      -- ^ An interpolation fraction indicating where, for @band@ scales, axis ticks should+      --   be position. A value of @0@ places ticks at the left-edge of the band, @0.5@ in+      --   the middle, and @1@ at the right edge.+      --+      --   @since 0.4.0.0+    | AxDataCondition BooleanOp ConditionalAxisProperty+      -- ^ Set conditions on an axis property. The first argument is the+      --   test to apply, and the second is the pair of properties+      --   to set if the condition holds or not.+      --+      --   The test parameter has access to the axis @value@ and @label@+      --   properties: that is+      --+      --   @+      --   'PAxis' [ 'AxDataCondition'+      --             ('Expr' "datum.value <= 2")+      --             ('CAxTickColor' "red" "blue")+      --         , 'AxDataCondition'+      --             ('Expr' "datum.label == '4.0'")+      --             ('CAxTickWidth' 5 2)+      --         ]+      --   @+      --+      --   Inline aggregation can be performed (before the test)+      --   using 'FilterOpTrans', which can be particularly useful for+      --   filtering temporal data. The following example will use solid+      --   grid lines for the first day in January, and dashes for+      --   all other dates (using 'Data.Function.&'):+      --+      --   @+      --   'PAxis' [ 'AxDataCondition'+      --             ('FEqual' "value" ('Graphics.Vega.VegaLite.DateTime' ['Grahics.Vega.VegaLite.DTMonth' 'Graphics.Vega.VegaLite.Jan', 'Graphics.Vega.VegaLite.DTDate' 1])+      --             & 'FilterOpTrans' ('MTimeUnit' 'Graphics.Vega.VegaLite.MonthDate'))+      --             ('CAxGridDash' [] [2, 2])+      --         ]+      --   @+      --+      --   @since 0.5.0.0+    | AxDomain Bool+      -- ^ Should the axis domain (the baseline) be displayed?+    | AxDomainColor Color+      -- ^ The axis domain color.+      --+      --   @since 0.4.0.0+    | AxDomainDash DashStyle+      -- ^ The dash pattern of the domain.+      --+      --   @since 0.4.0.0+    | AxDomainDashOffset DashOffset+      -- ^ The offset for the dash pattern.+      --+      --   @since 0.4.0.0+    | AxDomainOpacity Opacity+      -- ^ The axis domain opacity.+      --+      --   @since 0.4.0.0+    | AxDomainWidth Double+      -- ^ The width of the axis domain.+      --+      --   @since 0.4.0.0+    | AxFormat T.Text+      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html) for+      --   axis values. To distinguish between formatting as numeric values+      --   and data/time values, additionally use 'AxFormatAsNum' or 'AxFormatAsTemporal'.+    | AxFormatAsNum+      -- ^ Facet headers should be formatted as numbers. Use a+      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)+      --   with 'AxFormat'.+      --+      -- @since 0.4.0.0+    | AxFormatAsTemporal+      -- ^ Facet headers should be formatted as dates or times. Use a+      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)+      --   with 'AxFormat'.+      --+      -- @since 0.4.0.0+    | AxGrid Bool+      -- ^ Should an axis grid be displayed?+    | AxGridColor Color+      -- ^ The color for the grid.+      --+      --   @since 0.4.0.0+    | AxGridDash DashStyle+      -- ^ The dash pattern of the grid.+      --+      --   @since 0.4.0.0+    | AxGridDashOffset DashOffset+      -- ^ The offset for the dash pattern.+      --+      --   @since 0.4.0.0+    | AxGridOpacity Opacity+      -- ^ The opacity of the grid.+      --+      --   @since 0.4.0.0+    | AxGridWidth Double+      -- ^ The width of the grid lines.+      --+      --   @since 0.4.0.0+    | AxLabels Bool+      -- ^ Should labels be added to an axis?+    | AxLabelAlign HAlign+      -- ^ The horizontal alignment for labels.+      --+      --   @since 0.4.0.0+    | AxLabelAngle Angle+      -- ^ The angle at which to draw labels.+    | AxLabelBaseline VAlign+      -- ^ The vertical alignment for labels.+      --+      --   @since 0.4.0.0+    | AxLabelNoBound+      -- ^ No boundary overlap check is applied to labels. This is the+      --   default behavior.+      --+      --   See also 'AxLabelBound' and 'AxLabelBoundValue'.+      --+      --   @since 0.4.0.0+    | AxLabelBound+      -- ^ Labels are hidden if they exceed the axis range by more than 1+      --   pixel.+      --+      --   See also 'AxLabelNoBound' and 'AxLabelBoundValue'.+      --+      --   @since 0.4.0.0+    | AxLabelBoundValue Double+      -- ^ Labels are hidden if they exceed the axis range by more than+      --   the given number of pixels.+      --+      --   See also 'AxLabelNoBound' and 'AxLabelBound'.+      --+      --   @since 0.4.0.0+    | AxLabelColor Color+      -- ^ The label color.+      --+      --   @since 0.4.0.0+    | AxLabelExpr VegaExpr+      -- ^ Provide the expression used to generate axis labels.+      --+      --   The expression can use @datum.value@ and @datum.label@ to access+      --   the data value and default label text respectively.+      --+      --   The following example uses four digit years for decades and+      --   two-digit years for other years:+      --+      --   @+      --   AxLabelExpr "if(year(datum.value) % 10 == 0, utcFormat(datum.value,'%Y'), utcFormat(datum.value,'%y'))"+      --   @+      --+      --   @since 0.5.0.0+    | AxLabelNoFlush+      -- ^ The labels are not aligned flush to the scale. This is the+      --   default for non-continuous X scales.+      --+      --   See also 'AxLabelFlush' and 'AxLabelFlushValue'.+      --+      --   @since 0.4.0.0+    | AxLabelFlush+      -- ^ The first and last axis labels are aligned flush to the scale+      --   range.+      --+      --   See also 'AxLabelNoFlush' and 'AxLabelFlushValue'.+      --+      --   @since 0.4.0.0+    | AxLabelFlushValue Double+      -- ^ The labels are aligned flush, and the parameter determines+      --   the extra offset, in pixels, to apply to the first and last+      --   labels. This can help the labels better group (visually) with+      --   the corresponding axis ticks.+      --+      --   See also 'AxLabelNoFlush' and 'AxLabelFlush'.+      --+      --   @since 0.4.0.0+    | AxLabelFlushOffset Double+      -- ^ The number of pixels to offset flush-adjusted labels.+      --+      --   @since 0.4.0.0+    | AxLabelFont T.Text+      -- ^ The font for the label.+      --+      --   @since 0.4.0.0+    | AxLabelFontSize Double+      -- ^ The font size of the label.+      --+      --   @since 0.4.0.0+    | AxLabelFontStyle T.Text+      -- ^ The font style of the label.+      --+      --   @since 0.4.0.0+    | AxLabelFontWeight FontWeight+      -- ^ The font weight of the label.+      --+      --   @since 0.4.0.0+    | AxLabelLimit Double+      -- ^ The maximum width of a label, in pixels.+      --+      --   @since 0.4.0.0+    | AxLabelOpacity Opacity+      -- ^ The opacity of the label.+      --+      --   @since 0.4.0.0+    | AxLabelOverlap OverlapStrategy+      -- ^ How should overlapping labels be displayed?+    | AxLabelPadding Double+      -- ^ The padding, in pixels, between the label and the axis.+    | AxLabelSeparation Double+      -- ^ The minimum separation, in pixels, between label bounding boxes+      --   for them to be considered non-overlapping. This is ignored if+      --   the 'AxLabelOverlap' strategy is 'Graphics.Vega.VegaLite.ONone'.+      --+      --   @since 0.4.0.0+    | AxMaxExtent Double+      -- ^ The maximum extent, in pixels, that axis ticks and labels should use.+      --   This determines a maxmium offset value for axis titles.+    | AxMinExtent Double+      -- ^ The minimum extent, in pixels, that axis ticks and labels should use.+      --   This determines a minmium offset value for axis titles.+    | AxOffset Double+      -- ^ The offset, in pixels, between the axis and the edge of the+      --   enclosing group or data rectangle.+    | AxOrient Side+      -- ^ The orientation of the axis.+    | AxPosition Double+      -- ^ The anchor position of the axis in pixels.+    | AxTicks Bool+      -- ^ Should tick marks be drawn on an axis?+    | AxTickBand BandAlign+      -- ^ For band scales, indicates if ticks and grid lines should be+      --   placed at the center of a band (the default) or at the band+      --   extents to indicate intervals.+      --+      --   @since 0.5.0.0+    | AxTickColor Color+      -- ^ The color of the ticks.+      --+      --   @since 0.4.0.0+    | AxTickCount Int+      -- ^ The desired number of ticks for axes visualizing quantitative scales.+      --   This is a hint to the system, and the actual number used will be+      --   adjusted to be \"nice\" (multiples of 2, 5, or 10) and lie within the+      --   underlying scale's range.+    | AxTickDash DashStyle+      -- ^ The dash pattern of the ticks.+      --+      --   @since 0.4.0.0+    | AxTickDashOffset DashOffset+      -- ^ The offset for the dash pattern.+      --+      --   @since 0.4.0.0+    | AxTickExtra Bool+      -- ^ Should an extra axis tick mark be added for the initial position of+      --   the axis?+      --+      --   @since 0.4.0.0+    | AxTickMinStep Double+      -- ^ The minimum desired step between axis ticks, in terms of the scale+      --   domain values.+      --+      --   @since 0.4.0.0+    | AxTickOffset Double+      -- ^ The position offset, in pixels, to apply to ticks, labels, and grid lines.+      --+      --   @since 0.4.0.0+    | AxTickOpacity Opacity+      -- ^ The opacity of the ticks.+      --+      --   @since 0.4.0.0+    | AxTickRound Bool+      -- ^ Should pixel position values be rounded to the nearest integer?+      --+      --   @since 0.4.0.0+    | AxTickSize Double+      -- ^ The size of the tick marks in pixels.+    | AxTickWidth Double+      -- ^ The width of the tick marks in pixels.+      --+      --   @since 0.4.0.0+    | AxTitle T.Text+      -- ^ The axis title.+    | AxNoTitle+      -- ^ Draw no title for the axis.+      --+      --   @since 0.4.0.0+    | AxTitleAlign HAlign+      -- ^ The horizontal alignment of the axis title.+    | AxTitleAnchor APosition+      -- ^ The text anchor position for placing axis titles.+      --+      --   @since 0.4.0.0+    | AxTitleAngle Angle+      -- ^ The angle of the axis title.+    | AxTitleBaseline VAlign+      -- ^ The vertical alignment of the axis title.+      --+      --   @since 0.4.0.0+    | AxTitleColor Color+      -- ^ The color of the axis title.+      --+      --   @since 0.4.0.0+    | AxTitleFont T.Text+      -- ^ The font for the axis title.+      --+      --   @since 0.4.0.0+    | AxTitleFontSize Double+      -- ^ The font size of the axis title.+      --+      --   @since 0.4.0.0+    | AxTitleFontStyle T.Text+      -- ^ The font style of the axis title.+      --+      --   @since 0.4.0.0+    | AxTitleFontWeight FontWeight+      -- ^ The font weight of the axis title.+      --+      --   @since 0.4.0.0+    | AxTitleLimit Double+      -- ^ The maximum allowed width of the axis title, in pixels.+      --+      --   @since 0.4.0.0+    | AxTitleLineHeight Double+      -- ^ Line height, in pixels, for multi-line title text.+      --+      --   @since 0.5.0.0+    | AxTitleOpacity Opacity+      -- ^ The opacity of the axis title.+      --+      --   @since 0.4.0.0+    | AxTitlePadding Double+      -- ^ The padding, in pixels, between title and axis.+    | AxTitleX Double+      -- ^ The X coordinate of the axis title, relative to the axis group.+      --+      --   @since 0.4.0.0+    | AxTitleY Double+      -- ^ The Y coordinate of the axis title, relative to the axis group.+      --+      --   @since 0.4.0.0+    | AxTranslateOffset Double+      -- ^ The translation offset in pixels applied to the axis group+      --   mark x and y. If specified it overrides the default value+      --   of a 0.5 offset to pixel-align stroked lines.+      --+      --   @since 0.5.0.0+    | AxValues DataValues+      -- ^ Set the explicit tick, grid, and label values along an axis.+      --+      --   The following three examples are for an axis displaying a+      --   quantitative, categorical, and temporal field respectively.+      --+      --   @+      --   'PAxis' ['AxValues' ('Numbers' [2, 3, 5, 7, 11, 13, 17])]+      --   'PAxis' ['AxValues' ('Strings' ["cats", "dogs", "elephants"])]+      --   'PAxis' ['AxValues' ('DateTimes' [ ['Graphics.Vega.VegaLite.DTYear' 2019, 'Graphics.Vega.VegaLite.DTMonth' 'Graphics.Vega.VegaLite.Mar', 'Graphics.Vega.VegaLite.DTDate' 31]+      --                              , ['Graphics.Vega.VegaLite.DTYear' 2019, 'Graphics.Vega.VegaLite.DTMonth' 'Graphics.Vega.VegaLite.Jun', 'Graphics.Vega.VegaLite.DTDate' 30]+      --                              , ['Graphics.Vega.VegaLite.DTYear' 2019, 'Graphics.Vega.VegaLite.DTMonth' 'Graphics.Vega.VegaLite.Sep', 'Graphics.Vega.VegaLite.DTDate' 30]+      --                              ])]+      --   @+      --+      --   Changed in @0.4.0.0@ to take 'DataValues' rather than @[Double]@.+    | AxDates [[DateTime]]+      -- ^ The dates or times to appear along the axis.+      --+      --   As of version @0.4.0.0@, this is deprecated. The 'AxValues'+      --   constructor should be used instead.+    | AxZIndex ZIndex+      -- ^ The z-index of the axis, relative to the chart marks.+++axisProperty :: AxisProperty -> LabelledSpec+axisProperty (AxBandPosition x) = "bandPosition" .= x+axisProperty (AxDataCondition predicate cap) =+  let (ifAxProp, elseAxProp) = conditionalAxisProperty cap+      (axKey, ifProp) = axisProperty ifAxProp+      (_, elseProp) = axisProperty elseAxProp+  in axKey .= object [ "condition" .= object [ "test" .= booleanOpSpec predicate+                                             , "value" .= ifProp+                                             ]+                     , "value" .= elseProp]+axisProperty (AxDomain b) = "domain" .= b+axisProperty (AxDomainColor s) = "domainColor" .= fromColor s+axisProperty (AxDomainDash ds) = "domainDash" .= fromDS ds+axisProperty (AxDomainDashOffset x) = "domainDashOffset" .= x+axisProperty (AxDomainOpacity x) = "domainOpacity" .= x+axisProperty (AxDomainWidth x) = "domainWidth" .= x+axisProperty (AxFormat fmt) = "format" .= fmt+axisProperty AxFormatAsNum = "formatType" .= fromT "number"+axisProperty AxFormatAsTemporal = "formatType" .= fromT "time"+axisProperty (AxGrid b) = "grid" .= b+axisProperty (AxGridColor s) = "gridColor" .= fromColor s+axisProperty (AxGridDash ds) = "gridDash" .= fromDS ds+axisProperty (AxGridDashOffset x) = "gridDashOffset" .= x+axisProperty (AxGridOpacity x) = "gridOpacity" .= x+axisProperty (AxGridWidth x) = "gridWidth" .= x+axisProperty (AxLabels b) = "labels" .= b+axisProperty (AxLabelAlign ha) = "labelAlign" .= hAlignLabel ha+axisProperty (AxLabelAngle a) = "labelAngle" .= a+axisProperty (AxLabelBaseline va) = "labelBaseline" .= vAlignLabel va+axisProperty AxLabelNoBound = "labelBound" .= False+axisProperty AxLabelBound = "labelBound" .= True+axisProperty (AxLabelBoundValue x) = "labelBound" .= x+axisProperty (AxLabelColor s) = "labelColor" .= fromColor s+axisProperty (AxLabelExpr e) = "labelExpr" .= e+axisProperty AxLabelNoFlush = "labelFlush" .= False+axisProperty AxLabelFlush = "labelFlush" .= True+axisProperty (AxLabelFlushValue x) = "labelFlush" .= x+axisProperty (AxLabelFlushOffset x) = "labelFlushOffset" .= x+axisProperty (AxLabelFont s) = "labelFont" .= s+axisProperty (AxLabelFontSize x) = "labelFontSize" .= x+axisProperty (AxLabelFontStyle s) = "labelFontStyle" .= s+axisProperty (AxLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw+axisProperty (AxLabelLimit x) = "labelLimit" .= x+axisProperty (AxLabelOpacity x) = "labelOpacity" .= x+axisProperty (AxLabelOverlap s) = "labelOverlap" .= overlapStrategyLabel s+axisProperty (AxLabelPadding x) = "labelPadding" .= x+axisProperty (AxLabelSeparation x) = "labelSeparation" .= x+axisProperty (AxMaxExtent n) = "maxExtent" .= n+axisProperty (AxMinExtent n) = "minExtent" .= n+axisProperty (AxOffset n) = "offset" .= n+axisProperty (AxOrient side) = "orient" .= sideLabel side+axisProperty (AxPosition n) = "position" .= n+axisProperty (AxTicks b) = "ticks" .= b+axisProperty (AxTickBand bnd) = "tickBand" .= bandAlignLabel bnd+axisProperty (AxTickColor s) = "tickColor" .= fromColor s+axisProperty (AxTickCount n) = "tickCount" .= n+axisProperty (AxTickDash ds) = "tickDash" .= fromDS ds+axisProperty (AxTickDashOffset x) = "tickDashOffset" .= x+axisProperty (AxTickExtra b) = "tickExtra" .= b+axisProperty (AxTickMinStep x) = "tickMinStep" .= x+axisProperty (AxTickOffset x) = "tickOffset" .= x+axisProperty (AxTickOpacity x) = "tickOpacity" .= x+axisProperty (AxTickRound b) = "tickRound" .= b+axisProperty (AxTickSize x) = "tickSize" .= x+axisProperty (AxTickWidth x) = "tickWidth" .= x+axisProperty (AxTitle ttl) = "title" .= splitOnNewline ttl+axisProperty AxNoTitle = "title" .= A.Null+axisProperty (AxTitleAlign ha) = "titleAlign" .= hAlignLabel ha+axisProperty (AxTitleAnchor a) = "titleAnchor" .= anchorLabel a+axisProperty (AxTitleAngle x) = "titleAngle" .= x+axisProperty (AxTitleBaseline va) = "titleBaseline" .= vAlignLabel va+axisProperty (AxTitleColor s) = "titleColor" .= fromColor s+axisProperty (AxTitleFont s) = "titleFont" .= s+axisProperty (AxTitleFontSize x) = "titleFontSize" .= x+axisProperty (AxTitleFontStyle s) = "titleFontStyle" .= s+axisProperty (AxTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw+axisProperty (AxTitleLimit x) = "titleLimit" .= x+axisProperty (AxTitleLineHeight x) = "titleLineHeight" .= x+axisProperty (AxTitleOpacity x) = "titleOpacity" .= x+axisProperty (AxTitlePadding pad) = "titlePadding" .= pad+axisProperty (AxTitleX x) = "titleX" .= x+axisProperty (AxTitleY x) = "titleY" .= x+axisProperty (AxTranslateOffset x) = "translate" .= x+axisProperty (AxValues vals) = "values" .= dataValuesSpecs vals+axisProperty (AxDates dtss) = "values" .= map (object . map dateTimeProperty) dtss+axisProperty (AxZIndex z) = "zindex" .= z+++{-|++For use with 'AxDataCondition', and defines those axis properties+which can be conditioned on their position (or label).++The constuctor determines the axis property (a label, tick, or+grid element), the second is the value to set if the condition+is 'True', and the third is the value for when it is 'False'.++@since 0.5.0.0+-}++-- The 4.0.2 Vega Lite spec does not correctly map the conditional+-- label align, so that CAxLabelAlign will generate an invalid JSON+-- file. This has been fixed (presumably for 4.0.3); see+-- https://github.com/vega/vega-lite/issues/5717++data ConditionalAxisProperty+  = CAxGridColor Color Color+    -- ^ The color for the axis grid.+  | CAxGridDash DashStyle DashStyle+    -- ^ The dash pattern for the axis grid.+  | CAxGridDashOffset DashOffset DashOffset+    -- ^ The offset for the dash pattern.+  | CAxGridOpacity Opacity Opacity+    -- ^ The opacity of the axis grid.+  | CAxGridWidth Double Double+    -- ^ The width of the axis grid.+  | CAxLabelAlign HAlign HAlign+    -- ^ Axis label horizontal alignment.+  | CAxLabelBaseline VAlign VAlign+    -- ^ Axis label vertical alignment.+  | CAxLabelColor Color Color+    -- ^ Axis label color.+  | CAxLabelFont T.Text T.Text+    -- ^ Axis label font.+  | CAxLabelFontSize Double Double+    -- ^ Axis label font.+  | CAxLabelFontStyle T.Text T.Text+    -- ^ Axis label font style.+  | CAxLabelFontWeight FontWeight FontWeight+    -- ^ Axis label font weight.+  | CAxLabelOpacity Opacity Opacity+    -- ^ Axis label opacity.+  | CAxTickColor T.Text T.Text+    -- ^ Tick color for the axis.+  | CAxTickDash DashStyle DashStyle+    -- ^ The dash pattern for the axis ticks.+  | CAxTickDashOffset DashOffset DashOffset+    -- ^ The offset for the dash pattern.+  | CAxTickOpacity Opacity Opacity+    -- ^ Opacity of the axis tick marks.+  | CAxTickWidth Double Double+    -- ^ Width of the axis tick marks.+++conditionalAxisProperty :: ConditionalAxisProperty -> (AxisProperty, AxisProperty)+conditionalAxisProperty (CAxGridColor t f) = (AxGridColor t, AxGridColor f)+conditionalAxisProperty (CAxGridDash t f) = (AxGridDash t, AxGridDash f)+conditionalAxisProperty (CAxGridDashOffset t f) = (AxGridDashOffset t, AxGridDashOffset f)+conditionalAxisProperty (CAxGridOpacity t f) = (AxGridOpacity t, AxGridOpacity f)+conditionalAxisProperty (CAxGridWidth t f) = (AxGridWidth t, AxGridWidth f)+conditionalAxisProperty (CAxLabelAlign t f) = (AxLabelAlign t, AxLabelAlign f)+conditionalAxisProperty (CAxLabelBaseline t f) = (AxLabelBaseline t, AxLabelBaseline f)+conditionalAxisProperty (CAxLabelColor t f) = (AxLabelColor t, AxLabelColor f)+conditionalAxisProperty (CAxLabelFont t f) = (AxLabelFont t, AxLabelFont f)+conditionalAxisProperty (CAxLabelFontSize t f) = (AxLabelFontSize t, AxLabelFontSize f)+conditionalAxisProperty (CAxLabelFontStyle t f) = (AxLabelFontStyle t, AxLabelFontStyle f)+conditionalAxisProperty (CAxLabelFontWeight t f) = (AxLabelFontWeight t, AxLabelFontWeight f)+conditionalAxisProperty (CAxLabelOpacity t f) = (AxLabelOpacity t, AxLabelOpacity f)+conditionalAxisProperty (CAxTickColor t f) = (AxTickColor t, AxTickColor f)+conditionalAxisProperty (CAxTickDash t f) = (AxTickDash t, AxTickDash f)+conditionalAxisProperty (CAxTickDashOffset t f) = (AxTickDashOffset t, AxTickDashOffset f)+conditionalAxisProperty (CAxTickOpacity t f) = (AxTickOpacity t, AxTickOpacity f)+conditionalAxisProperty (CAxTickWidth t f) = (AxTickWidth t, AxTickWidth f)+++{-|++Declare the way the view is sized. See the+<https://vega.github.io/vega-lite/docs/size.html#autosize Vega-Lite documentation>+for details.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'width' 250+    , 'height' 300+    , 'autosize' [ 'Graphics.Vega.VegaLite.AFit', 'Graphics.Vega.VegaLite.APadding', 'Graphics.Vega.VegaLite.AResize' ]+    , 'Graphics.Vega.VegaLite.dataFromUrl' "data/population.json" []+    , 'mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+autosize :: [Autosize] -> PropertySpec+autosize aus = (VLAutosize, object (map autosizeProperty aus))+++-- | The background style of a single view or layer in a view composition.+--+--   @since 0.4.0.0++viewBackground :: [ViewBackground] -> PropertySpec+viewBackground vbs = (VLViewBackground, object (map viewBackgroundSpec vbs))+++{-|++Used for creating logical compositions. For example++@+'color'+    [ 'MSelectionCondition' (Or ('SelectionName' "alex") (SelectionName "morgan"))+        ['MAggregate' 'Count', 'MName' "*", 'MmType' 'Graphics.Vega.VegaLite.Quantitative']+        ['MString' "gray"]+    ]+@++Logical compositions can be nested to any level as shown in this example++@+'Not' ('And' ('Expr' "datum.IMDB_Rating === null") ('Expr' "datum.Rotten_Tomatoes_Rating === null") )+@+-}+data BooleanOp+    = Expr VegaExpr+      -- ^ Expression that should evaluate to either true or false.+    | FilterOp Filter+      -- ^ Convert a 'Filter' into a 'BooleanOp' so that it may be used as+      --   part of a more complex expression.+      --+      --   For example (using 'Data.Function.&' to apply 'FilterOp' to a filter):+      --+      --   @+      --   trans = 'transform'+      --             . 'filter' ('FCompose'+      --                        ('And'+      --                          ('FValid' "IMDB_Rating" & 'FilterOp')+      --                          ('FValid' "Rotten_Tomatoes_Rating" & 'FilterOp')+      --                        )+      --                      )+      --   @+      --+      --   @since 0.4.0.0+    | FilterOpTrans MarkChannel Filter+      -- ^ Combine a data-transformation operation with a filter before+      --   converting into a boolean operation. This can be useful when+      --   working with dates, such as the following exampe, which aggregates+      --   a set of dates into years, and filters only those years between+      --   2010 and 2017 (inclusive). The final expression is converted+      --   back into a 'BooleanOp' with 'FCompose' (combined using+      --   'Data.Function.&').+      --+      --   @+      --   'filter' ('FRange' "date" ('DateRange' ['Graphics.Vega.VegaLite.DTYear' 2010] ['Graphics.Vega.VegaLite.DTYear' 2017])+      --           & 'FilterOpTrans' ('MTimeUnit' 'Graphics.Vega.VegaLite.Year')+      --           & 'FCompose'+      --           )+      --   @+      --+      --   @since 0.4.0.0+    | Selection SelectionLabel  -- TODO: rename Selected since collides with Selection type+      -- ^ Interactive selection that will be true or false as part of+      --   a logical composition.  For example: to filter a dataset so+      --   that only items selected interactively and that have a+      --   weight of more than 30:+      --+      -- @+      -- 'transform'+      --    . 'filter' ('FCompose' ('And' ('Selection' "brush") ('Expr' "datum.weight > 30")))+      -- @+    | SelectionName SelectionLabel+    -- ^  Name a selection that is used as part of a conditional encoding.+    --+    -- @+    -- 'color'+    --    [ 'MSelectionCondition' ('SelectionName' \"myBrush\")+    --        ['MName' \"myField\", 'MmType' 'Graphics.Vega.VegaLite.Nominal']+    --        ['MString' \"grey\"]+    --    ]+    -- @+    | And BooleanOp BooleanOp+      -- ^ Apply an \'and\' Boolean operation as part of a logical composition.+      --+      -- @+      -- 'And' ('Expr' "datum.IMDB_Rating === null") ('Expr' "datum.Rotten_Tomatoes_Rating === null")+      -- @+    | Or BooleanOp BooleanOp+      -- ^ Apply an \'or\' Boolean operation as part of a logical composition.+    | Not BooleanOp+      -- ^ Negate the given expression.+      --+      -- @+      -- 'Not' ('And' ('Expr' "datum.IMDB_Rating === null") ('Expr' "datum.Rotten_Tomatoes_Rating === null"))+      -- @++booleanOpSpec :: BooleanOp -> VLSpec+booleanOpSpec (Expr expr) = toJSON expr+booleanOpSpec (FilterOp f) = filterSpec f+booleanOpSpec (FilterOpTrans tr f) = trFilterSpec tr f+booleanOpSpec (SelectionName selName) = toJSON selName+booleanOpSpec (Selection sel) = object ["selection" .= sel]+booleanOpSpec (And operand1 operand2) = object ["and" .= [booleanOpSpec operand1, booleanOpSpec operand2]]+booleanOpSpec (Or operand1 operand2) = object ["or" .= [booleanOpSpec operand1, booleanOpSpec operand2]]+booleanOpSpec (Not operand) = object ["not" .= booleanOpSpec operand]+++{-|++Type of filtering operation. See the+<https://vega.github.io/vega-lite/docs/filter.html Vega-Lite documentation>+for details.++These can also be included into a 'BooleanOp' expression using 'FilterOp'+and 'FilterOpTrans'+(as of version @0.4.0.0@).++-}+data Filter+    = FEqual FieldName DataValue+      -- ^ Filter a data stream so that only data in a given field equal to+      --   the given value are used.+    | FLessThan FieldName DataValue+      -- ^ Filter a data stream so that only data in a given field less than the given+      --   value are used.+      --+      --   @since 0.4.0.0+    | FLessThanEq FieldName DataValue+      -- ^ Filter a data stream so that only data in a given field less than,+      --   or equal to, the given value are used.+      --+      --   @since 0.4.0.0+    | FGreaterThan FieldName DataValue+      -- ^ Filter a data stream so that only data in a given field greater than the given+      --   value are used.+      --+      --   @since 0.4.0.0+    | FGreaterThanEq FieldName DataValue+      -- ^ Filter a data stream so that only data in a given field greater than,+      --   or equal to, the given value are used.+      --+      --   @since 0.4.0.0+    | FExpr VegaExpr+      -- ^ Filter a data stream so that only data that satisfy the given predicate+      --   expression are used.+    | FCompose BooleanOp+      -- ^ Build up a filtering predicate through logical composition such+      --   as 'And' and 'Or'.+      --+      --   The following fgragment will apply a filter to identify only+      --   those items selected interactively and that represent ages+      --   over 65:+      --+      --   @+      --   trans = 'transform'+      --             . 'filter'+      --                 ('FCompose'+      --                   ('And' ('Selection' "brush") ('Expr' "datum.age > 65"))+      --                 )+      --   @+    | FSelection SelectionLabel+      -- ^ Filter a data stream so that only data in a given field that are+      --   within the given interactive selection are used.+      --+      --   @+      --   sel = 'Graphics.Vega.VegaLite.selection' . 'Graphics.Vega.VegaLite.select' \"myBrush\" 'Graphics.Vega.VegaLite.Interval' ['Graphics.Vega.VegaLite.Encodings' ['Graphics.Vega.VegaLite.ChX']]+      --   trans = 'transform' . 'filter' ('FSelection' \"myBrush\")+      --   @+    | FOneOf FieldName DataValues+      -- ^ Filter a data stream so that only data in a given field contained in the given+      --   list of values are used.+    | FRange FieldName FilterRange+      -- ^ Filter a data stream so that only data in a given field+      --   that are within the given range are used.+      --+      --   For example:+      --+      --   @+      --   'filter' ('FRange' "date" ('DateRange' ['Graphics.Vega.VegaLite.DTYear' 2006] ['Graphics.Vega.VegaLite.DTYear' 2016])+      --   @+      --+      --   See 'FilterOpTrans' for more use cases.+    | FValid FieldName+      -- ^ Filter a data stream so that only valid data (i.e. not null or NaN) in a given+      --   field are used.+      --+      --   @since 0.4.0.0+++fop_ :: FieldName -> T.Text -> DataValue -> [LabelledSpec]+fop_ field label val = [field_ field, label .= dataValueSpec val]++filterProperty :: Filter -> [LabelledSpec]++filterProperty (FEqual field val) = fop_ field "equal" val+filterProperty (FLessThan field val) = fop_ field "lt" val+filterProperty (FLessThanEq field val) = fop_ field "lte" val+filterProperty (FGreaterThan field val) = fop_ field "gt" val+filterProperty (FGreaterThanEq field val) = fop_ field "gte" val++filterProperty (FSelection selName) = ["selection" .= selName]++filterProperty (FRange field vals) =+  let ans = case vals of+              NumberRange mn mx -> map toJSON [mn, mx]+              DateRange dMin dMax -> [process dMin, process dMax]++      process [] = A.Null+      process dts = object (map dateTimeProperty dts)++  in [field_ field, "range" .= ans]++filterProperty (FOneOf field vals) =+  let ans = case vals of+              Numbers xs -> map toJSON xs+              DateTimes dts -> map (object . map dateTimeProperty) dts+              Strings ss -> map toJSON ss+              Booleans bs -> map toJSON bs++  in [field_ field, "oneOf" .= ans]++filterProperty (FValid field) = [field_ field, "valid" .= True]+filterProperty _ = []  -- ignore FExpr and FCompose+++filterSpec :: Filter -> VLSpec+filterSpec (FExpr expr) = toJSON expr+filterSpec (FCompose boolExpr) = booleanOpSpec boolExpr+filterSpec f = object (filterProperty f)++trFilterSpec :: MarkChannel -> Filter -> VLSpec+trFilterSpec _ (FExpr expr) = toJSON expr+trFilterSpec _ (FCompose boolExpr) = booleanOpSpec boolExpr+trFilterSpec mchan fi = object (markChannelProperty mchan <> filterProperty fi)+++{-|++A pair of filter range data values. The first argument is the inclusive minimum+vale to accept and the second the inclusive maximum.+-}+data FilterRange+    = NumberRange Double Double+    | DateRange [DateTime] [DateTime]+++-- | Types of hyperlink channel property used for linking marks or text to URLs.++data HyperlinkChannel+    = HName FieldName+      -- ^ Field used for encoding with a hyperlink channel.+    | HRepeat Arrangement+      -- ^ Reference in a hyperlink channel to a field name generated by 'repeatFlow'+      --  or 'repeat'. The parameter identifies whether reference is being made to+      -- fields that are to be arranged in columns, in rows, or a with a flow layout.+    | HmType Measurement+      -- ^ Level of measurement when encoding with a hyperlink channel.+    | HBin [BinProperty]+      -- ^ Discretize numeric values into bins when encoding with a hyperlink channel.+    | HBinned+      -- ^ Indicate that data encoded with a hyperlink channel are already binned.+      --+      --   @since 0.4.0.0+    | HAggregate Operation+      -- ^ Compute aggregate summary statistics for a field to be encoded with a+      -- hyperlink channel.+    | HTimeUnit TimeUnit+    | HSelectionCondition BooleanOp [HyperlinkChannel] [HyperlinkChannel]+      -- ^ Make a hyperlink channel conditional on interactive selection. The first parameter+      --   provides the selection to evaluate, the second the encoding to apply if the hyperlink+      --   has been selected, the third the encoding if it is not selected.+    | HDataCondition [(BooleanOp, [HyperlinkChannel])] [HyperlinkChannel]+      -- ^ Make a hyperlink channel conditional on one or more predicate expressions. The first+      --   parameter is a list of tuples each pairing an expression to evaluate with the encoding+      --   if that expression is @True@. The second is the encoding if none of the expressions+      --   evaluate as @True@.+      --+      --   The arguments to this constructor have changed in @0.4.0.0@+      --   to support multiple expressions.+    | HString T.Text+      -- ^ Literal string value when encoding with a hyperlink channel.++hyperlinkChannelProperty :: HyperlinkChannel -> [LabelledSpec]+hyperlinkChannelProperty (HName s) = [field_ s]+hyperlinkChannelProperty (HRepeat arr) = ["field" .= object [repeat_ arr]]+hyperlinkChannelProperty (HmType t) = [mtype_ t]+hyperlinkChannelProperty (HBin bps) = [bin bps]+hyperlinkChannelProperty HBinned = [binned_]+hyperlinkChannelProperty (HSelectionCondition selName ifClause elseClause) =+  selCond_ hyperlinkChannelProperty selName ifClause elseClause+hyperlinkChannelProperty (HDataCondition tests elseClause) =+  dataCond_ hyperlinkChannelProperty tests elseClause+hyperlinkChannelProperty (HTimeUnit tu) = [timeUnit_ tu]+hyperlinkChannelProperty (HAggregate op) = [aggregate_ op]+hyperlinkChannelProperty (HString s) = [value_ s]+++----++{-|++Create a pair of continuous domain to color mappings suitable for customising+ordered scales. The first parameter is a tuple representing the mapping of the lowest+numeric value in the domain to its equivalent color; the second tuple the mapping+of the highest numeric value to color. If the domain contains any values between+these lower and upper bounds they are interpolated according to the scale's interpolation+function. This is a convenience function equivalent to specifying separate 'SDomain'+and 'SRange' lists and is safer as it guarantees a one-to-one correspondence between+domain and range values.++@+'color'+    [ 'MName' "year"+    , 'MmType' 'Graphics.Vega.VegaLite.Ordinal'+    , 'MScale' (domainRangeMap (1955, \"rgb(230,149,156)\") (2000, \"rgb(145,26,36)\"))+    ]+@+-}++domainRangeMap :: (Double, Color) -> (Double, Color) -> [ScaleProperty]+domainRangeMap lowerMap upperMap =+  let (domain, range) = unzip [lowerMap, upperMap]+  in [SDomain (DNumbers domain), SRange (RStrings range)]+++{-|++Create a set of discrete domain to color mappings suitable for customising categorical+scales. The first item in each tuple should be a domain value and the second the+color value with which it should be associated. It is a convenience function equivalent+to specifying separate 'SDomain' and 'SRange' lists and is safer as it guarantees+a one-to-one correspondence between domain and range values.++@+'color'+    [ 'MName' "weather"+    , 'MmType' Nominal+    , 'MScale' (+        categoricalDomainMap+            [ ( "sun", "yellow" )+            , ( "rain", "blue" )+            , ( "fog", "grey" )+            ]+        )+    ]+@+-}++categoricalDomainMap :: [(T.Text, Color)] -> [ScaleProperty]+categoricalDomainMap scaleDomainPairs =+  let (domain, range) = unzip scaleDomainPairs+  in [SDomain (DStrings domain), SRange (RStrings range)]+++{-|++Types of facet channel property used for creating a composed facet view of small+multiples.++-}++-- based on schema 3.3.0 #/definitions/FacetFieldDef++data FacetChannel+    = FName FieldName+      -- ^ The name of the field from which to pull a data value.+    | FmType Measurement+      -- ^ The encoded field's type of measurement.+    | FAggregate Operation+      -- ^ Aggregation function for the field.+    | FBin [BinProperty]+      -- ^ Describe how to bin quantitative fields, or whether the+      --   channels are already binned.+    | FHeader [HeaderProperty]+      -- ^ The properties of a facet's header.+    | FSort [SortProperty]+      -- ^ Sort order for the encoded field.+      --+      --   @since 0.4.0.0+    | FTimeUnit TimeUnit+      -- ^ The time-unit for a temporal field.+    | FTitle T.Text+      -- ^ The title for the field.+      --+      --   @since 0.4.0.0+    | FNoTitle+      -- ^ Draw no title.+      --+      -- @since 0.4.0.0++facetChannelProperty :: FacetChannel -> LabelledSpec+facetChannelProperty (FName s) = field_ s+facetChannelProperty (FmType measure) = mtype_ measure+facetChannelProperty (FAggregate op) = aggregate_ op+facetChannelProperty (FBin bps) = bin bps+facetChannelProperty (FHeader hps) = header_ hps+facetChannelProperty (FSort sps) = sort_ sps+facetChannelProperty (FTitle s) = "title" .= s+facetChannelProperty FNoTitle = "title" .= A.Null+facetChannelProperty (FTimeUnit tu) = timeUnit_ tu+++-- | Types of text channel property used for displaying text as part of the visualization.++-- Basing the following partly on vega-lite-3.3.0.json / TextFieldDef+-- but that doesn't seem to be sufficient.++data TextChannel+    = TName FieldName+      -- ^ Name of the field used for encoding with a text channel.+    | TAggregate Operation+      -- ^ Compute some aggregate summary statistics for a field to be encoded with a+      --   text channel. The type of aggregation is determined by the given operation+      --   parameter.+    | TBin [BinProperty]+      -- ^ Discretize numeric values into bins when encoding with a text channel.+    | TBinned+      -- ^ Indicate that data encoded with a text channel are already binned.+      --+      --   @since 0.4.0.0+    | TDataCondition [(BooleanOp, [TextChannel])] [TextChannel]+      -- ^ Make a text channel conditional on one or more predicate expressions. The first+      --   parameter is a list of tuples each pairing an expression to evaluate with the encoding+      --   if that expression is @True@. The second is the encoding if none of the expressions+      --   evaluate as @True@.+      --+      --   The arguments to this constructor have changed in @0.4.0.0@+      --   to support multiple expressions.+    | TFormat T.Text+      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html)+      --   for text marks. To distinguish between formatting as numeric values and data/time+      --   values, additionally use 'TFormatAsNum' or 'TFormatAsTemporal'.+    | TFormatAsNum+      -- ^ The text marks should be formatted as numbers. Use a+      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)+      --   with 'TFormat'.+      --+      -- @since 0.4.0.0+    | TFormatAsTemporal+      -- ^ The text marks should be formatted as dates or times. Use a+      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)+      --   with 'TFormat'.+      --+      -- @since 0.4.0.0+    | TmType Measurement+      -- ^ Level of measurement when encoding with a text channel.+    | TRepeat Arrangement+      -- ^ Reference in a text channel to a field name generated by 'repeatFlow'+      --   or 'repeat'. The parameter identifies whether reference is being made to+      --   fields that are to be arranged in columns, in rows, or a with a flow layout.+    | TSelectionCondition BooleanOp [TextChannel] [TextChannel]+      -- ^ Make a text channel conditional on interactive selection. The first parameter+      --   is a selection condition to evaluate; the second the encoding to apply if that+      --   selection is true; the third parameter is the encoding if the selection is false.+    | TTitle T.Text+      -- ^ Title of a field when encoding with a text or tooltip channel.+      --+      --   @since 0.4.0.0+    | TNoTitle+      -- ^ Display no title.+      --+      --   @since 0.4.0.0+    | 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+      --+      --   This can be useful for a text annotation, such as:+      --+      --   @+      --   'encoding'+      --      . 'position' 'Graphics.Vega.VegaLite.X' [ 'PNumber' 300 ]+      --      . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PNumber' 1234 ]+      --      . 'text' [ 'TString' \"Upper limit\" ]+      --   @+      --+      --   @since 0.5.0.0++textChannelProperty :: TextChannel -> [LabelledSpec]+textChannelProperty (TName s) = [field_  s]+textChannelProperty (TAggregate op) = [aggregate_ op]+textChannelProperty (TBin bps) = [bin bps]+textChannelProperty TBinned = [binned_]+textChannelProperty (TFormat fmt) = ["format" .= fmt]+textChannelProperty TFormatAsNum = ["formatType" .= fromT "number"]+textChannelProperty TFormatAsTemporal = ["formatType" .= fromT "time"]+textChannelProperty (TmType measure) = [mtype_ measure]+textChannelProperty (TRepeat arr) = ["field" .= object [repeat_ arr]]+textChannelProperty (TTitle s) = ["title" .= splitOnNewline s]+textChannelProperty TNoTitle = ["title" .= A.Null]+textChannelProperty (TTimeUnit tu) = [timeUnit_ tu]+textChannelProperty (TDataCondition tests elseClause) =+  dataCond_ textChannelProperty tests elseClause+textChannelProperty (TSelectionCondition selName ifClause elseClause) =+  selCond_ textChannelProperty selName ifClause elseClause+textChannelProperty (TString s) = ["value" .= s]+++-- | Properties of an ordering channel used for sorting data fields.++data OrderChannel+    = OName FieldName+      -- ^ The name of the field used for encoding with an order channel.+    | ORepeat Arrangement+      -- ^ Reference in an order channel to a field name generated by 'repeatFlow'+      -- or 'repeat'. The parameter identifies whether reference is being made to+      -- fields that are to be arranged in columns, in rows, or a with a flow layout.+    | OmType Measurement+      -- ^ The level of measurement when encoding with an order channel.+    | OBin [BinProperty]+      -- ^ Discretize numeric values into bins when encoding with an+      --   order channel.+    | OAggregate Operation+      -- ^ Compute some aggregate summary statistics for a field to be encoded+      --   with an order channel.+    | OTimeUnit TimeUnit+      -- ^ Form of time unit aggregation of field values when encoding with+      --   an order channel.+    | OSort [SortProperty]+      -- ^ Sort order for field when encoding with an order channel.+++orderChannelProperty :: OrderChannel -> LabelledSpec+orderChannelProperty (OName s) = field_ s+orderChannelProperty (ORepeat arr) = "field" .= object [repeat_ arr]+orderChannelProperty (OmType measure) = mtype_ measure+orderChannelProperty (OBin bps) = bin bps+orderChannelProperty (OAggregate op) = aggregate_ op+orderChannelProperty (OTimeUnit tu) = timeUnit_ tu+orderChannelProperty (OSort ops) = sort_ ops+++-- | Level of detail channel properties used for creating a grouped channel+--   encoding.++data DetailChannel+    = DName FieldName+      -- ^ The name of the field.+    | DmType Measurement+      -- ^ The measurement type of the field.+    | DBin [BinProperty]+      -- ^ How to convert discrete numeric values into bins.+    | DTimeUnit TimeUnit+      -- ^ The form of time unit aggregation.+    | DAggregate Operation+      -- ^ How should the detail field be aggregated?+++detailChannelProperty :: DetailChannel -> LabelledSpec+detailChannelProperty (DName s) = field_ s+detailChannelProperty (DmType t) = mtype_ t+detailChannelProperty (DBin bps) = bin bps+detailChannelProperty (DTimeUnit tu) = timeUnit_ tu+detailChannelProperty (DAggregate op) = aggregate_ op+++{-|++Provides details of the mapping between a row or column and its field+definitions in a set of faceted small multiples. For details see the+<https://vega.github.io/vega-lite/docs/facet.html#mapping Vega-Lite documentation>.+-}+data FacetMapping+    = ColumnBy [FacetChannel]+    | RowBy [FacetChannel]+++facetMappingProperty :: FacetMapping -> LabelledSpec+facetMappingProperty (RowBy fFields) =+  "row" .= object (map facetChannelProperty fFields)+facetMappingProperty (ColumnBy fFields) =+  "column" .= object (map facetChannelProperty fFields)+++{-|++Create a single global configuration from a list of configuration specifications.+Configurations are applied to all relevant items in the specification. See the+<https://vega.github.io/vega-lite/docs/config.html Vega-Lite documentation> for+more details.++The following example would make axis lines (domain) 2 pixels wide,+remove the border rectangle and require interactive selection of items+to use a double-click:++@+config =+    'configure'+        . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.Axis' [ 'Graphics.Vega.VegaLite.DomainWidth' 1 ])+        . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.View' [ 'Graphics.Vega.VegaLite.ViewStroke' (Just "transparent") ])+        . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.SelectionStyle' [ ( 'Graphics.Vega.VegaLite.Single', [ 'Graphics.Vega.VegaLite.On' \"dblclick\" ] ) ])+@+-}++configure ::+  [ConfigureSpec]+  -- ^ The configuration options, created with 'Graphics.Vega.VegaLite.configuration'.+  --+  --    Prior to version @0.5.0.0@ this was @[LabelledSpec]@.+  -> PropertySpec+configure configs = (VLConfig, object (map unCS configs))+++-- | Alignment to apply to grid rows and columns generated by a composition+--   operator. This version sets the same alignment for rows and columns.+--+--   See also 'alignRC'.+--+--   @since 0.4.0.0++align :: CompositionAlignment -> PropertySpec+align algn = (VLAlign, compositionAlignmentSpec algn)+++-- | Similar to 'align' but with independent alignments for rows and columns.+--+--   See also 'align'.+--+--   @since 0.4.0.0++alignRC ::+  CompositionAlignment     -- ^ Row alignment+  -> CompositionAlignment  -- ^ Column alignment+  -> PropertySpec+alignRC alRow alCol =+  (VLSpacing, object [ "row" .= compositionAlignmentSpec alRow+                     , "col" .= compositionAlignmentSpec alCol+                     ])+++-- | Spacing between sub-views in a composition operator.+--+--   See also 'spacingRC'.+--+--   @since 0.4.0.0++spacing ::+  Double   -- ^ Spacing in pixels.+  -> PropertySpec+spacing sp = (VLSpacing, toJSON sp)+++-- | Set the spacing between the rows and columns.+--+--   See also 'spacing'.+--+--   @since 0.4.0.0++spacingRC ::+  Double      -- ^ Spacing between rows (in pixels).+  -> Double   -- ^ Spacing between columns (in pixels).+  -> PropertySpec+spacingRC spRow spCol = (VLSpacing, object ["row" .= spRow, "column" .= spCol])+++-- | Are sub-views in a composition operator centred relative to their respective+--   rows and columns?+--+--   See also 'centerRC'.+--+--   @since 0.4.0.0++center :: Bool -> PropertySpec+center c = (VLCenter, toJSON c)+++-- | Are sub-views in a composition operator centred relative to their respective+--   rows and columns?+--+--   See also 'center'.+--+--   @since 0.4.0.0++centerRC ::+  Bool     -- ^ Are rows to be centered?+  -> Bool  -- ^ Are columns to be centered?+  -> PropertySpec+centerRC cRow cCol = (VLCenter, object ["row" .= cRow, "col" .= cCol])+++{-|++Bounds calculation method to use for determining the extent of a sub-plot in+a composed view.++@since 0.4.0.0+-}+bounds :: Bounds -> PropertySpec+bounds bnds = (VLBounds, boundsSpec bnds)+++{-|++The list of specifications to be juxtaposed horizontally in a flow+layout of views.+See also 'hConcat' and 'vConcat'.++The number of columns in the flow layout can be set with 'columns'+and, if not specified, will default to a single row of unlimited columns.++@+let dvals = 'Graphics.Vega.VegaLite.dataSequenceAs' 0 6.28 0.1 \"x\"+    trans = 'transform'+              . 'calculateAs' \"sin(datum.x)\" \"sinX\"+              . 'calculateAs' \"cos(datum.x)\" \"cosX\"+    enc = 'encoding'+            . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"x\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+    encCos = enc . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"cosX\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+    encSin = enc . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"sinX\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']++in toVegaLite [ dvals+              , trans []+              , 'vlConcat' [ 'Graphics.Vega.VegaLite.asSpec' [encCos [], 'mark' 'Graphics.Vega.VegaLite.Line' []]+                         , 'Graphics.Vega.VegaLite.asSpec' [encSin [], 'mark' 'Graphics.Vega.VegaLite.Line' []]+                         ]+              ]+@++This is named @concat@ in Elm VegaLite but has been renamed here+to avoid conflicting with the Prelude.++@since 0.4.0.0++-}+vlConcat :: [VLSpec] -> PropertySpec+vlConcat specs = (VLConcat, toJSON specs)+++{-|++Defines the fields that will be used to facet a view in rows or columns to create+a set of small multiples. This is used where the encoding of the visualization in small+multiples is identical, but data for each is grouped by the given fields. When+creating a faceted view in this way you also need to define a full specification+to apply to each of those facets using 'Graphics.Vega.VegaLite.asSpec'.++See the+<https://vega.github.io/vega-lite/docs/facet.html Vega-Lite documentation>+for further details.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ facet [ 'RowBy' [ 'FName' \"Month\", 'FmType' 'Graphics.Vega.VegaLite.Ordinal' ]+            , 'ColumnBy' [ 'FName' \"Week\", 'FmType' 'Graphics.Vega.VegaLite.Ordinal' ]+            ]+    , 'Graphics.Vega.VegaLite.specification' spec+    ]+@++See also 'facetFlow'.++-}++facet :: [FacetMapping] -> PropertySpec+facet fMaps = (VLFacet, object (map facetMappingProperty fMaps))+++{-|++Facet a view to create small multiples in a flow layout. Used when the encoding+of the visualization in small multiples is identical, but data for each is grouped+by the given fields. When creating a faceted view in this way you also need to+define a full specification to apply to each of those facets using 'Graphics.Vega.VegaLite.asSpec'.++Small multiples will be laid out from left to right, moving on to new rows only+if the number of plots exceeds an optional column limit (specified via 'columns').++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ facetFlow [ 'FName' \"Origin\", 'FmType' 'Graphics.Vega.VegaLite.Nominal' ]+    , 'Graphics.Vega.VegaLite.specification' spec+    ]+@++See also 'facet'.++@since 0.4.0.0+-}+facetFlow :: [FacetChannel] -> PropertySpec+facetFlow fFields = (VLFacet, object (map facetChannelProperty fFields))+++{-|++Overrides the default height of the visualization. If not specified the height+will be calculated based on the content of the visualization. See+'autosize' for customization of the content sizing relative to this+setting, 'heightOfContainer' for setting the height to that of+the surrounding container,+and 'heightStep' for setting the height of discrete fields.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'height' 300+    , 'Graphics.Vega.VegaLite.dataFromUrl' "data/population.json" []+    , 'mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+height :: Double -> PropertySpec+height h = (VLHeight, toJSON h)+++{-|+Set the height of the view to that of the surrounding container,+to allow for responsive sizing.++Please see the [Vega Lite responsive sizing](https://vega.github.io/vega-lite/docs/size.html#specifying-responsive-width-and-height)+documentation for caveats and limitations.++@since 0.5.0.0+-}+heightOfContainer :: PropertySpec+heightOfContainer = (VLHeight, fromT "container")+++{-|++Set the height of the discrete y-field (e.g. individual bars in a+horizontal bar chart).+The total height is then calculated based on the number of discrete fields+(e.g. bars).++@+'Graphics.Vega.VegaLite.toVegaLite'+  [ 'heightStep' 17+  , data []+  , enc []+  , 'mark' 'Graphcs.Vega.VegaLite.Bar' []+  ]+@++This replaces the use of @SRangeStep@ from 'ScaleProperty'.++@since 0.5.0.0+-}++-- Note that unlike ELm, we do not create a separate property here+-- (ie no VLHeightStep)+--+heightStep :: Double -> PropertySpec+heightStep s = (VLHeight, object [ "step" .= s ])+++{-|++Assigns a list of specifications to be juxtaposed horizontally in a visualization.+See also 'vConcat' and 'vlConcat'.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'Graphics.Vega.VegaLite.dataFromUrl' "data/driving.json" []+    , hConcat [ spec1, spec2 ]+    ]+@+-}+hConcat :: [VLSpec] -> PropertySpec+hConcat specs = (VLHConcat, toJSON specs)+++{-|++Assigns a list of specifications to superposed layers in a visualization.++@+'Graphics.Vega.VegaLite.toVegaLite' ['Graphics.Vega.VegaLite.dataFromUrl' "data/driving.json" [], layer [spec1, spec2]]+@++A complete example showing @layer@ in use:++@+let dvals = 'Graphics.Vega.VegaLite.dataFromColumns' []+              . 'Graphics.Vega.VegaLite.dataColumn' \"x\" ('Numbers' [1, 2, 3, 4, 5])+              . 'Graphics.Vega.VegaLite.dataColumn' \"a\" ('Numbers' [28, 91, 43, 55, 81])+    enc = 'encoding'+             . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"x\", 'PmType' 'Graphics.Vega.VegaLite.Ordinal']+             . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"a\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+             . 'text' ['TName' \"a\", 'TmType' 'Graphics.Vega.VegaLite.Nominal']++    in 'Graphics.Vega.VegaLite.toVegaLite' [ dvals []+                  , enc []+                  , 'layer' [ 'Graphics.Vega.VegaLite.asSpec' ['mark' 'Graphics.Vega.VegaLite.Bar' []]+                          , 'Graphics.Vega.VegaLite.asSpec' ['mark' 'Graphics.Vega.VegaLite.Text' ['Graphics.Vega.VegaLite.MdY' (-8)]]+                          ]+                  ]+@++-}+layer :: [VLSpec] -> PropertySpec+layer specs = (VLLayer, toJSON specs)+++{-|++Provides an optional name to be associated with the visualization.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'name' \"PopGrowth\"+    , 'Graphics.Vega.VegaLite.dataFromUrl' \"data/population.json\" []+    , 'mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+name :: T.Text -> PropertySpec+name s = (VLName, toJSON s)+++{-|++Set the padding around the visualization in pixel units. The way padding is+interpreted will depend on the 'autosize' properties. See the+<https://vega.github.io/vega-lite/docs/spec.html#top-level-specifications Vega-Lite documentation>+for details.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'width' 500+    , 'padding' ('Graphics.Vega.VegaLite.PEdges' 20 10 5 15)+    , 'Graphics.Vega.VegaLite.dataFromUrl' "data/population.json" []+    , 'mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+padding :: Padding -> PropertySpec+padding pad = (VLPadding, paddingSpec pad)+++{-|++Define the fields that will be used to compose rows and columns of a+set of small multiples. This is used where the encoding of the+visualization in small multiples is largely identical, but the data+field used in each might vary. When a list of fields is identified+with @repeat@ you also need to define a full specification to apply to+each of those fields using 'Graphics.Vega.VegaLite.asSpec'.++Unlike __faceting__, which creates multiple charts based on different values of a+single field, __repeating__ uses a different field for each chart.++See the+<https://vega.github.io/vega-lite/docs/repeat.html Vega-Lite documentation>+for further details.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'repeat' ['Graphics.Vega.VegaLite.ColumnFields' [\"Cat\", \"Dog\", \"Fish\"]]+    , 'Graphics.Vega.VegaLite.specification' ('Graphics.Vega.VegaLite.asSpec' spec)+    ]+@++See also 'repeatFlow'.++-}++repeat :: [RepeatFields] -> PropertySpec+repeat fields = (VLRepeat, object (map repeatFieldsProperty fields))+++{-|++Define the fields that will be used to compose a flow layout of a set of+small multiples. Used when the encoding is largely identical, but the data field+used in each might vary. When a list of fields is identified with @repeatFlow@ you also+need to define a full specification to apply to each of those fields using 'Graphics.Vega.VegaLite.asSpec'.++Small multiples will be laid out from left to right, moving on to new rows only+if the number of plots exceeds an optional column limit (specified via 'columns').++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'repeatFlow' [ \"Cat\", \"Dog\", \"Fish\" ]+    , 'Graphics.Vega.VegaLite.specification' ('Graphics.Vega.VegaLite.asSpec' spec)+    ]+@++See also 'repeat'.++@since 0.4.0.0++-}+repeatFlow ::+  [FieldName]+  -> PropertySpec+repeatFlow fields = (VLRepeat, toJSON fields)+++{-|++Determine whether scales, axes or legends in composite views should+share channel encodings. This allows, for example, two different color+encodings to be created in a layered view, which otherwise by default+would share color channels between layers. Each resolution rule should+be in a tuple pairing the channel to which it applies and the rule+type.++@+let res = 'resolve'+            . 'resolution' ('Graphics.Vega.VegaLite.RLegend' [('Graphics.Vega.VegaLite.ChColor', 'Graphics.Vega.VegaLite.Independent')])++in 'Graphics.Vega.VegaLite.toVegaLite'+    [ 'Graphics.Vega.VegaLite.dataFromUrl' \"data/movies.json\" []+    , 'vConcat' [heatSpec, barSpec]+    , res []+    ]+@++For more information see the+<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation>.++@+let dvals = 'Graphics.Vega.VegaLite.dataFromColumns' []+              . 'Graphics.Vega.VegaLite.dataColumn' "x" ('Numbers' [1, 2, 3, 4, 5])+              . 'Graphics.Vega.VegaLite.dataColumn' "a" ('Numbers' [28, 91, 43, 55, 81])+              . 'Graphics.Vega.VegaLite.dataColumn' "b" ('Numbers' [17, 22, 28, 30, 40])+    encBar = 'encoding'+               . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"x\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+               . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"a\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+    specBar = 'Graphics.Vega.VegaLite.asSpec' ['mark' 'Graphics.Vega.VegaLite.Bar' [], encBar []]+    encLine = 'encoding'+                . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"x\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+                . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"b\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+    specLine = 'Graphics.Vega.VegaLite.asSpec' ['mark' 'Graphics.Vega.VegaLite.Line' ['Graphics.Vega.VegaLite.MColor' \"firebrick\"], encLine []]+    res = 'resolve'+            . 'resolution' ('Graphics.Vega.VegaLite.RScale' [('Graphics.Vega.VegaLite.ChY', 'Graphics.Vega.VegaLite.Independent')])++in 'Graphics.Vega.VegaLite.toVegaLite' [dvals [], res [], 'layer' [specBar, specLine]]+@++-}+resolve ::+  [ResolveSpec]+  -- ^ The arguments created by 'Graphics.Vega.VegaLite.resolution'.+  --+  --   Prior to @0.5.0.0@ this argument was @['LabelledSpec']@.+  -> PropertySpec+resolve res = (VLResolve, object (map unRS res))+++{-|++Create a single transform from a list of transformation+specifications. Note that the order of transformations can be+important, especially if labels created with 'calculateAs',+'timeUnitAs', and 'binAs' are used in other transformations.  Using+the functional composition pipeline idiom (as example below) allows+you to provide the transformations in the order intended in a clear+manner.++@+'transform'+    . 'filter' ('FExpr' "datum.year == 2010")+    . 'calculateAs' "datum.sex == 2 ? \'Female\' : \'Male\'" "gender"+@++The supported transformations are:+'aggregate', 'binAs', 'calculateAs', 'density', 'filter', 'flatten',+'flattenAs', 'fold', 'foldAs', 'impute', 'joinAggregate', 'loess',+'lookup', 'lookupAs', 'lookupSelection', 'pivot', 'quantile',+'regression', 'sample', 'stack', 'timeUnitAs', and 'window'.++-}++transform ::+  [TransformSpec]+  -- ^ The transformations to apply. The order does matter.+  --+  --   Prior to @0.5.0.0@ this argument was @['LabelledSpec']@.+  -> PropertySpec+transform transforms =+  let js = if null transforms then A.Null else toJSON (map unTS transforms)+  in (VLTransform, js)+++{-|++Assigns a list of specifications to be juxtaposed vertically in a visualization.+See also 'hConcat' and 'vlConcat'.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'Graphics.Vega.VegaLite.dataFromUrl' "data/driving.json" []+    , 'vConcat' [ spec1, spec2 ]+    ]+@+-}+vConcat :: [VLSpec] -> PropertySpec+vConcat specs = (VLVConcat, toJSON specs)+++{-|++Override the default width of the visualization. If not specified the width+will be calculated based on the content of the visualization. See+'autosize' for customization of the content sizing relative to this+setting, 'widthOfContainer' for setting the width to that of+the surrounding container,+and 'widthStep' for setting the width of discrete fields.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'width' 500+    , 'Graphics.Vega.VegaLite.dataFromUrl' "data/population.json" []+    , 'mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+width :: Double -> PropertySpec+width w = (VLWidth, toJSON w)+++{-|+Set the width of the view to that of the surrounding container,+to allow for responsive sizing.++Please see the [Vega Lite responsive sizing](https://vega.github.io/vega-lite/docs/size.html#specifying-responsive-width-and-height)+documentation for caveats and limitations.++@since 0.5.0.0+-}+widthOfContainer :: PropertySpec+widthOfContainer = (VLWidth, fromT "container")+++{-|++Set the width of the discrete x-field (e.g. individual bars in a bar chart).+The total width is then calculated based on the number of discrete fields+(e.g. bars).++@+'Graphics.Vega.VegaLite.toVegaLite'+  [ 'widthStep' 17+  , data []+  , enc []+  , 'mark' 'Graphcs.Vega.VegaLite.Bar' []+  ]+@++This replaces the use of @SRangeStep@ from 'ScaleProperty'.++@since 0.5.0.0+-}++-- Note that unlike ELm, we do not create a separate property here+-- (ie no VLWidthStep)+--+widthStep :: Double -> PropertySpec+widthStep s = (VLWidth, object [ "step" .= s ])+++{-|++Defines a set of named aggregation transformations to be used when encoding+channels. This is useful when, for example, you wish to apply the same transformation+to a number of channels but do not want to define it each time. For further details+see the+<https://vega.github.io/vega-lite/docs/aggregate.html#aggregate-op-def Vega-Lite documentation>.++@+'transform'+    . 'aggregate'+        [ 'opAs' 'Graphics.Vega.VegaLite.Min' "people" "lowerBound"+        , 'opAs' 'Graphics.Vega.VegaLite.Max' "people" "upperBound" ]+        [ "age" ]+@++See also 'joinAggregate'.++-}+aggregate ::+  [VLSpec]+  -- ^ The named aggregation operations to apply.+  -> [FieldName]+  -- ^ The \"group by\" fields.+  -> BuildTransformSpecs+aggregate ops groups ols =+  let fields = [ "aggregate" .= ops+               , "groupby" .= groups ]+  in TS (object fields) : ols+++{-|++Aggregation transformations to be used when encoding channels. Unlike+'aggregate', this transformation joins the results to the input data.+Can be helpful for creating derived values that combine raw data with some aggregate+measure, such as percentages of group totals. The first parameter is a list+of the named aggregation operations to apply. The second is a list of possible+window aggregate field properties, such as a field to group by when aggregating.+The third parameter is a list of transformations to which this is added.++@+'transform'+    . 'joinAggregate'+        [ 'opAs' 'Graphics.Vega.VegaLite.Mean' "rating" "avYearRating" ]+        [ 'Graphics.Vega.VegaLite.WGroupBy' [ "year" ] ]+    . 'filter' ('FExpr' "(datum.rating - datum.avYearRating) > 3"))+@++For details, see the+<https://vega.github.io/vega-lite/docs/joinaggregate.html Vega-Lite join aggregate documentation>.++See also 'aggregate'.++@since 0.4.0.0+-}++joinAggregate ::+  [VLSpec]+  -> [WindowProperty]+  -> BuildTransformSpecs+joinAggregate ops wProps ols = joinAggregateTS ops wProps : ols+++{-|++Window transform for performing calculations over sorted groups of+data objects such as ranking, lead/lag analysis, running sums and averages.++@+'transform'+    . 'window' [ ( [ 'Graphics.Vega.VegaLite.WAggregateOp' 'Graphics.Vega.VegaLite.Sum', 'Graphics.Vega.VegaLite.WField' \"Time\" ], \"TotalTime\" ) ]+             [ 'Graphics.Vega.VegaLite.WFrame' Nothing Nothing ]+@++@since 0.4.0.0++-}+window ::+  [([Window], FieldName)]+  -- ^ The window-transform definition and associated output name.+  -> [WindowProperty]+  -- ^ The window transform.+  -> BuildTransformSpecs+window wss wProps ols = windowTS wss wProps : ols+++{-|++Randomly sample rows from a data source up to a given maximum.++For example, the following randomly samples 50 values from a sine curve:++@+ dvals = 'Graphics.Vega.VegaLite.dataSequenceAs' 0 13 0.001 \"x\"+ trans = 'transform'+           . 'calculateAs' \"sin(datum.x)\" \"y\"+           . 'sample' 50+@++@since 0.4.0.0++-}++sample :: Int -> BuildTransformSpecs+sample maxSize ols = TS (object [ "sample" .= maxSize ]) : ols+++{-|++Configure the kernel density estimation process. Used by 'density'.++@since 0.5.0.0+-}++data DensityProperty+  = DnAs FieldName FieldName+    -- ^ Name the outputs of a density transform. The first argument is the+    --   name of the field containing the samples and the second the name+    --   for the field containing the density estimates.+    --+    --   The defaults are @\"value\"@ and @\"density\"@ respectively.+  | DnBandwidth Double+    -- ^ The bandwidth (standard deviation) of the Gaussian kernel to be+    --   used in the KDE. If not given, or set to 0, then+    --   [Scott's method](https://stats.stackexchange.com/questions/90656/kernel-bandwidth-scotts-vs-silvermans-rules)+    --   is used.+  | DnCounts Bool+    -- ^ If @'True'@ then the KDE generates counts, if @'False'@ it+    --   generates probabilities.+    --+    --   The default is probabilities.+  | DnCumulative Bool+    -- ^ Should the density estimates be cumulative?+    --+    --   The default is @'False'@.+  | DnExtent Double Double+    -- ^ The domain (minimum to maximum) from which to sample a distribution+    --   for the density estimation.+    --+    --   The default is to use the full extent of the input values.+  | DnGroupBy [FieldName]+    -- ^ The data fields to group by.+    --+    --   The default is to use a single group containing all the data objects.+  | DnMaxSteps Natural+    -- ^ The maximum number of samples to take from the extent domain.+    --+    --   The default is 200.+  | DnMinSteps Natural+    -- ^ The minimum number of samples to take from the extent domain.+    --+    --   The default is 25.+  | DnSteps Natural+    -- ^ This overrides the 'DnMinSteps' and 'DnMaxSteps' options and+    --   specified an exact number of steps to take from the extent+    --   domain.+    --+    --   It can be used with 'DnExtent' to ensure a consistent+    --   set of sample points for stacked densities.+++data DensityPropertyLabel =+  DPLGroupby | DPLCumulative | DPLCounts | DPLBandwidth | DPLExtent |+  DPLMinsteps | DPLMaxsteps | DPLSteps | DPLAs+++densityPropertySpec :: DensityPropertyLabel -> [DensityProperty] -> VLSpec+densityPropertySpec DPLGroupby ps =+  let wanted (DnGroupBy xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLCumulative ps =+  let wanted (DnCumulative xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLCounts ps =+  let wanted (DnCounts xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLBandwidth ps =+  let wanted (DnBandwidth xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLExtent ps =+  let wanted (DnExtent xs ys) = Just [xs, ys]+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLMinsteps ps =+  let wanted (DnMinSteps xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLMaxsteps ps =+  let wanted (DnMaxSteps xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLSteps ps =+  let wanted (DnSteps xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++densityPropertySpec DPLAs ps =+  let wanted (DnAs xs ys) = Just [xs, ys]+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++++{-|++Apply /Kernel Density Estimation/ to a data stream to generate a new stream+of samples of the estimated density. This is useful for representing+probability distributions and generating continuous distributions from+discrete samples.++The following example creates a faceted display of the smoothed+length and width distributions from the iris dataset.++@+dvals = 'Graphics.Vega.VegaLite.dataFromUrl' \"https:\/\/vega.github.io\/vega-lite\/data\/iris.json" []++colNames = [ \"petalWidth\", \"petalLength\", \"sepalWidth\", \"sepalLength\" ]+trans = 'transform'+        . 'foldAs' colNames \"measurement\" \"value\"+        . 'density' \"value\" [ 'DnGroupBy' [ \"measurement\" ] ]++enc = 'encoding'+      . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"value\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+      . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"density\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+      . 'row' [ 'FName' \"measurement\", 'FmType' 'Graphics.Vega.VegaLite.Nominal' ]++layer = 'Graphics.Vega.VegaLite.asSpec' [ trans [], enc [], 'mark' 'Graphics.Vega.VegaLite.Area' [ 'Graphics.Vega.VegaLite.MOpacity' 0.7 ] ]+@++@since 0.5.0.0+-}++density ::+  FieldName+  -- ^ The field used for the KDE.+  -> [DensityProperty]+  -- ^ Configure the calculation.+  -> BuildTransformSpecs+density field dps ols =+  let addField n p = case densityPropertySpec p dps of+                       A.Null -> []+                       x -> [ n .= x ]++      ofields = [ "density" .= field ]+                <> addField "groupby" DPLGroupby+                <> addField "cumulative" DPLCumulative+                <> addField "counts" DPLCounts+                <> addField "bandwidth" DPLBandwidth+                <> addField "extent" DPLExtent+                <> addField "minsteps" DPLMinsteps+                <> addField "maxsteps" DPLMaxsteps+                <> addField "steps" DPLSteps+                <> addField "as" DPLAs++  in TS (object ofields) : ols+++{-|++Configure the trend fitting used by the 'loess' encoding.++@since 0.5.0.0+-}+data LoessProperty+  = LsAs FieldName FieldName+    -- ^ Name the outputs of a loess transform. The first argument is the+    --   name of the field containing the smoothed independent variable+    --   and the second the name for the field containing the smoothed+    --   dependent variable.+    --+    --   If not specified the original field names will be used.+  | LsBandwidth Double+    -- ^ The amount of smoothing. The value should be in the range 0 to 1,+    --   inclusive.+    --+    --   The default is 0.3.+  | LsGroupBy [FieldName]+    -- ^ The data fields to group by.+    --+    --   The default is to use a single group containing all the data objects.+++data LoessPropertyLabel = LLAs | LLBandwidth | LLGroupBy++loessPropertySpec :: LoessPropertyLabel -> [LoessProperty] -> VLSpec+loessPropertySpec LLAs ps =+  let wanted (LsAs xs ys) = Just [xs, ys]+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++loessPropertySpec LLBandwidth ps =+  let wanted (LsBandwidth xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++loessPropertySpec LLGroupBy ps =+  let wanted (LsGroupBy xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null+++{-|++Generate a /loess/ (locally-estimated scatterplot smoothing) trendline+through a pair of data fields.++See also 'regression'.++The following example overlays the trendline generated by 'loess'+(the \"xsm\", \"ysm\" points) on the raw points (assuming the data+source has fields called \"xraw\" and \"yraw\" for the independent+and dependent fields, respectively).++@+transLS = 'transform'+          . 'loess' \"yraw\" \"xraw\" [ 'LsAs' \"xsm\" \"ysm\" ]++encRaw = 'encoding'+         . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"xraw\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+         . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"yraw\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]++encLS = 'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"xsm\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"ysm\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]++layers = 'layer' [ 'Graphics.Vega.VegaLite.asSpec' [ encRaw [], 'mark' 'Graphics.Vega.VegaLite.Point' [ 'Graphics.Vega.VegaLite.MOpacity' 0.5 ] ]+               , 'Graphics.Vega.VegaLite.asSpec' [ transLS [], encLS [], 'mark' 'Graphics.Vega.VegaLite.Line' [ 'Graphics.Vega.VegaLite.MColor' \"firebrick\" ] ]+               ]+@++@since 0.5.0.0+-}++loess ::+  FieldName+  -- ^ The field representing the dependent variable (often displayed on+  --   the y axis).+  -> FieldName+  -- ^ The field representing the independent variable (often the x axis).+  -> [LoessProperty]+  -- ^ Customize the trend fitting.+  -> BuildTransformSpecs+loess depField indField lsp ols =+  let addField n p = case loessPropertySpec p lsp of+                       A.Null -> []+                       x -> [ n .= x ]++      ofields = [ "loess" .= depField+                , "on" .= indField ]+                <> addField "groupby" LLGroupBy+                <> addField "bandwidth" LLBandwidth+                <> addField "as" LLAs++  in TS (object ofields) : ols+++{-|++The functional form of the regression analysis. Used by 'RgMethod'.++@since 0.5.0.0+-}+data RegressionMethod+  = RgLinear+    -- ^ Linear regression.+  | RgLog+    -- ^ Logarithmic regression.+  | RgExp+    -- ^ Exponential regression.+  | RgPow+    -- ^ Power regression.+  | RgQuad+    -- ^ Quadratic regression.+  | RgPoly+    -- ^ A polynomial. The order to use is given by the 'RgOrder'+    --   constructor, and defaults to 3.++regressionMethodSpec :: RegressionMethod -> VLSpec+regressionMethodSpec RgLinear = fromT "linear"+regressionMethodSpec RgLog = fromT "log"+regressionMethodSpec RgExp = fromT "exp"+regressionMethodSpec RgPow = fromT "pow"+regressionMethodSpec RgQuad = fromT "quad"+regressionMethodSpec RgPoly = fromT "poly"+++{-|++Configure the regression process (used by 'regression').++@since 0.5.0.0+-}++data RegressionProperty+  = RgAs FieldName FieldName+    -- ^ Name the outputs of the regression analysis. The first argument is the+    --   name of the field containing the independent variable, the second+    --   the dependent variable.+    --+    --   If not specified the original field names will be used.+  | RgExtent Double Double+    -- ^ The domain (minimum to maximum) over which to estimate the dependent+    --   variable in the regression.+    --+    --   The default is to use the full extent of the input values.+  | RgGroupBy [FieldName]+    -- ^ The data fields to group by.+    --+    --   The default is to use a single group containing all the data objects.+  | RgMethod RegressionMethod+    -- ^ The type of regression model to use.+  | RgOrder Natural+    -- ^ The order of the polynomial model.+    --+    --   This is only used if @'RgMethod' 'RgPoly'@ is set.+  | RgParams Bool+    -- ^ Should the transform return the regression model parameters, one object+    --   per group, rather than the trend line points.+    --+    --   If set, the returned objects include a @\"coef\"@ array of fitted+    --   coefficient values, starting with the intercept term and then including+    --   terms of increasing order, and a @\"rSquared\"@ value, indicating+    --   the total variance explained by the model.+    --+    --   The default is @'False'@.+++data RegressionPropertyLabel =+  RPLAs | RPLExtent | RPLGroupBy | RPLMethod | RPLOrder | RPLParams+++regressionPropertySpec :: RegressionPropertyLabel -> [RegressionProperty] -> VLSpec+regressionPropertySpec RPLAs ps =+  let wanted (RgAs xs ys) = Just [xs, ys]+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++regressionPropertySpec RPLExtent ps =+  let wanted (RgExtent xs ys) = Just [xs, ys]+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++regressionPropertySpec RPLGroupBy ps =+  let wanted (RgGroupBy xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++regressionPropertySpec RPLMethod ps =+  let wanted (RgMethod xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> regressionMethodSpec x+    _ -> A.Null++regressionPropertySpec RPLOrder ps =+  let wanted (RgOrder xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++regressionPropertySpec RPLParams ps =+  let wanted (RgParams xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null+++{-|++Generate a 2d regression model for smoothing and predicting data.++See also 'loess'.++The following example overlays the points generated by 'regression'+(the \"xrg\", \"yrg\" points) on the raw points (assuming the data+source has fields called \"xraw\" and \"yraw\" for the independent+and dependent fields, respectively).++@+transLS = 'transform'+          . 'regression' \"yraw\" \"xraw\" [ 'LsAs' \"xrg\" \"yrg\" ]++encRaw = 'encoding'+         . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"xraw\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+         . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"yraw\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]++encLS = 'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"xrg\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"yrg\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]++layers = 'layer' [ 'Graphics.Vega.VegaLite.asSpec' [ encRaw [], 'mark' 'Graphics.Vega.VegaLite.Point' [ 'Graphics.Vega.VegaLite.MOpacity' 0.5 ] ]+               , 'Graphics.Vega.VegaLite.asSpec' [ transLS [], encLS [], 'mark' 'Graphics.Vega.VegaLite.Line' [ 'Graphics.Vega.VegaLite.MColor' \"firebrick\" ] ]+               ]+@++@since 0.5.0.0+-}++regression ::+  FieldName+  -- ^ The field representing the dependent variable (often displayed on+  --   the y axis).+  -> FieldName+  -- ^ The field representing the independent variable (often the x axis).+  -> [RegressionProperty]+  -- ^ Customize the regression.+  -> BuildTransformSpecs+regression depField indField rps ols =+  let addField n p = case regressionPropertySpec p rps of+                       A.Null -> []+                       x -> [ n .= x ]++      ofields = [ "regression" .= depField+                , "on" .= indField ]+                <> addField "groupby" RPLGroupBy+                <> addField "method" RPLMethod+                <> addField "order" RPLOrder+                <> addField "extent" RPLExtent+                <> addField "params" RPLParams+                <> addField "as" RPLAs++  in TS (object ofields) : ols+++{-|+Configure the quantile analysis performed by 'quantile'.++@since 0.5.0.0+-}+data QuantileProperty+  = QtAs FieldName FieldName+    -- ^ Name the fields used to store the calculated probability and+    --   associated quantile values.+    --+    --   The defaults are @\"prob\"@ and @\"value\"@.+  | QtGroupBy [FieldName]+    -- ^ The data fields to group by.+    --+    -- The default is to use a single group containing all the data objects.+  | QtProbs [Double]+    -- ^ The probabilites (measured in the range 0-1) for which to+    --   compute quantile values.+    --+    --   The default is to use a step size of 0.01, or the+    --   'QtStep' value if given.+  | QtStep Double+    -- ^ The interval between probabilities when performing a quantile+    --   transformation.+    --+    --   All value from half the given step size to 1 will be sampled,+    --   and is only used if 'QtProbs' is not set.+++data QuantilePropertyLabel =+  QPLAs | QPLGroupBy | QPLProbs | QPLStep+++quantilePropertySpec :: QuantilePropertyLabel -> [QuantileProperty] -> VLSpec+quantilePropertySpec QPLAs ps =+  let wanted (QtAs xs ys) = Just [xs, ys]+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++quantilePropertySpec QPLGroupBy ps =+  let wanted (QtGroupBy xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++quantilePropertySpec QPLProbs ps =+  let wanted (QtProbs xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++quantilePropertySpec QPLStep ps =+  let wanted (QtStep xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null+++{-|+Calculate quantile values from an input data stream. This can be useful+for examining distributional properties of a data stream, and for+creating+<https://en.wikipedia.org/wiki/Q–Q_plot Q-Q plots>.++As an example:++@+let dvals = 'Graphics.Vega.VegaLite.dataFromUrl' \"data/normal-2d.json\" []++    trans = 'transform'+            . 'quantile' \"u\" [ 'QtStep' 0.01, 'QtAs' \"p\" \"v\" ]+            . 'calculateAs' \"quantileUniform(datum.p)\" \"unif\"+            . 'calculateAs' \"quantileNormal(datum.p)\" \"norm\"++    enc x y = 'encoding'+              . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' x, 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+              . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' y, 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]++    leftSpec = 'Graphics.Vega.VegaLite.asSpec' [ 'mark' 'Graphics.Vega.VegaLite.Point' [], enc \"unif\" \"v\" [] ]+    rightSpec = 'Graphics.Vega.VegaLite.asSpec' [ 'mark' 'Graphics.Vega.VegaLite.Point' [], enc \"norm\" \"v\" [] ]++in 'Graphics.Vega.VegaLite.toVegaLite' [ dvals, trans [], 'hConcat' [ leftSpec, rightSpec ] ]+@++@since 0.5.0.0+-}+quantile ::+  FieldName+  -- ^ The field to analyse.+  -> [QuantileProperty]+  -- ^ Configure the quantile analysis+  -> BuildTransformSpecs+quantile field qps ols =+  let addField n p = case quantilePropertySpec p qps of+                       A.Null -> []+                       x -> [ n .= x ]++      ofields = [ "quantile" .= field ]+                <> addField "groupby" QPLGroupBy+                <> addField "probs" QPLProbs+                <> addField "step" QPLStep+                <> addField "as" QPLAs++  in TS (object ofields) : ols+++{-|++Create a named binning transformation that may be referenced in other Transformations+or encodings. See the+<https://vega.github.io/vega-lite/docs/bin.html Vega-Lite documentation> for+more details. Note that usually, direct binning within an encoding is preferred+over this form of bin transformation.++@+'transform'+    . 'binAs' [ 'Graphics.Vega.VegaLite.MaxBins' 3 ] \"IMDB_Rating\" \"ratingGroup\"+@+-}+binAs ::+  [BinProperty]+  -- ^ An empty list means that the default binning is used (that is, the+  --   @bin@ field will be set to @true@ in the Vega-Lite specification).+  -> FieldName+  -- ^ The field to bin.+  -> FieldName+  -- ^ The label for the binned data.+  -> BuildTransformSpecs+binAs bProps field label ols =+  let fields = [ "bin" .= if null bProps then toJSON True else binObj+               , "field" .= field+               , "as" .= label ]++      binObj = object (map binProperty bProps)++ in TS (object fields) : ols+++{-|++Creates a new data field based on calculations from existing fields and values.++See the <https://vega.github.io/vega-lite/docs/calculate.html Vega-Lite documentation>+for further details.++@+'transform' . 'calculateAs' "datum.sex == 2 ? \'F\' : \'M\'" "gender"+@+-}+calculateAs ::+  VegaExpr+  -- ^ The calculation to perform.+  -> FieldName+  -- ^ The field to assign the new values.+  -> BuildTransformSpecs+calculateAs expr label ols =+  let fields = [ "calculate" .= expr, "as" .= label ]+  in TS (object fields) : ols+++{-|++Encode a color channel.++@+'color' [ 'MName' \"Species\", 'MmType' 'Graphics.Vega.VegaLite.Nominal' ] []+@++Encoding a color channel will generate a legend by default. To stop the legend+appearing, just supply an empty list of legend properties to 'MLegend':++@+'color' [ 'MName' \"Species\", 'MmType' 'Graphics.Vega.VegaLite.Nominal', 'MLegend' [] ] []+@+-}+color ::+  [MarkChannel]+  -- ^ The color-encoding options.+  -> BuildEncodingSpecs+color markProps ols = mchan_ "color" markProps : ols+++{-|++Encodes a new facet to be arranged in columns. See the+<https://vega.github.io/vega-lite/docs/facet.html#facet-row-and-column-encoding-channels Vega-Lite column documentation>.++Note that when faceting, dimensions specified with 'width' and 'height'+refer to the individual faceted plots, not the overall visualization.++@+let dvals = 'Graphics.Vega.VegaLite.dataFromUrl' \"crimeData.csv\"+    enc = 'encoding'+            . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"month\", 'PmType' 'Graphics.Vega.VegaLite.Temporal']+            . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"reportedCrimes\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative'+                         , 'PAggregate' 'Graphics.Vega.VegaLite.Sum']+            . 'column' ['FName' \"crimeType\", 'FmType' 'Graphics.Vega.VegaLite.Nominal']++    in 'Graphics.Vega.VegaLite.toVegaLite' ['width' 100, dvals [], 'mark' 'Graphics.Vega.VegaLite.Bar' [], enc [] ]+@+-}+column ::+  [FacetChannel]+  -- ^ The list of properties that define the faceting channel. At a minimum+  --   this should include the data field ('FName') and its measurement type+  --   ('FmType').+  -> BuildEncodingSpecs+column fFields ols =+  ES ("column", object (map facetChannelProperty fFields)) : ols+++{-|++The maximum number of columns to include in a view composition flow+layout. If the number of faceted small multiples exceeds this number,+flow moves to the next row.  Only applies to flow layouts generated by+'vlConcat', 'facetFlow', and 'repeatFlow'.++@since 0.4.0.0++-}++columns ::+  Natural+  -- ^ A value of 0 means that a single row will be used (which is also+  --   the default behavior).+  -> PropertySpec+columns cols = (VLColumns, toJSON cols)+++{-|++Encode a \"level of detail\" channel. This provides a way of grouping by a field+but unlike, say 'color', all groups have the same visual properties.++See the+<https://vega.github.io/vega-lite/docs/encoding.html#detail Vega-Lite documentation>+for details.++@+'detail' ['DName' \"Species\", 'DmType' 'Graphics.Vega.VegaLite.Nominal'] []+@+-}+detail ::+  [DetailChannel]+  -- ^ The field to group.+  -> BuildEncodingSpecs+detail detailProps ols =+    ES ("detail", object (map detailChannelProperty detailProps)) : ols+++{-++Elm added this in version 2.0, but I think it needs more structure+than just a field name, so am leaving out for now.++Encode a key channel, to support dynamic data via the+<https://vega.github.io/vega/docs/api/view/ Vega View API>.++See the <https://vega.github.io/vega-lite/docs/encoding.html#key Vega-Lite documentation>+for more information.++@+'encoding' . 'keyChannel' \"Species\"+@++@since 0.5.0.0+keyChannel ::+  FieldName+  -- ^ The field to use as the unique key for data binding.+  -> BuildLabelledSpecs+keyChannel f ols =+    ("key" .= object ["field" .= f]) : ols+    -- ("key" .= f) : ols++-}++{-|++Encode a fill channel. This acts in a similar way to encoding by 'color' but+only affects the interior of closed shapes.++@+'fill' [ 'MName' \"Species\", 'MmType' 'Graphics.Vega.VegaLite.Nominal' ] []+@++Note that if both @fill@ and 'color' encodings are specified, @fill@ takes precedence.++-}++fill ::+  [MarkChannel]+  -- ^ Configure the fill.+  -> BuildEncodingSpecs+fill markProps ols = mchan_ "fill" markProps : ols+++{-|++Encode a fill opacity channel. This acts in a similar way to encoding by 'opacity'+but only affects the interior of closed shapes. If both @fillOpacity@ and 'opacity'+encodings are specified, @fillOpacity@ takes precedence.++See also 'fill'.++@since 0.4.0.0+-}++fillOpacity :: [MarkChannel] -> BuildEncodingSpecs+fillOpacity markProps ols = mchan_ "fillOpacity" markProps : ols+++{-|++Adds the given filter operation a list of transformations that may be applied+to a channel or field.++@+'transform'+    . 'filter' ('FEqual' \"Animal\" ('Str' \"Cat\"))+@++Filter operations can combine selections and data predicates with 'BooleanOp'+expressions (and as of @0.4.0.0@, 'FilterOp' and 'FilterOpTrans'+can be used to lift the 'Filter' type into boolean expressions):++@+'transform'+    . 'filter' ('FCompose' ('And' ('Expr' "datum.Weight_in_lbs > 3000") ('Selection' "brush")))+@++The [Vega expression documentation](https://vega.github.io/vega/docs/expressions/)+describes the supported format (e.g. the requirement to precede column names+with @"datum."@).++-}+filter :: Filter -> BuildTransformSpecs+filter f ols = TS (object [ "filter" .= filterSpec f ]) : ols++++{-|++Map array-valued fields to a set of individual data objects, one per array entry.++See also 'flattenAs'.++@since 0.4.0.0++-}++flatten :: [FieldName] -> BuildTransformSpecs+flatten fields ols = TS (object [ "flatten" .= fields ]) : ols+++{-|++Similar to 'flatten' but allows the new output fields to be named.++@since 0.4.0.0++-}++flattenAs ::+  [FieldName]+  -> [FieldName]+  -- ^ The names of the output fields.+  -> BuildTransformSpecs+flattenAs fields names ols =+  let ofields = [ "flatten" .= fields, "as" .= names ]+  in TS (object ofields) : ols+++{-|++Perform a /gather/ operation to /tidy/ a table. Collapse multiple data fields+into two new data fields: @key@ containing the original data field names and+@value@ containing the corresponding data values.++It is the inverse of 'pivot'. See also 'foldAs'.++@+dvals =+    'Graphics.Vega.VegaLite.dataFromColumns' []+        . 'Graphics.Vega.VegaLite.dataColumn' \"city\" ('Strings' [ \"Bristol\", \"Sheffield\", \"Glasgow\" ])+        . 'Graphics.Vega.VegaLite.dataColumn' \"temp2017\" ('Numbers' [ 12, 11, 7 ])+        . 'Graphics.Vega.VegaLite.dataColumn' \"temp2018\" ('Numbers' [ 14, 13, 10 ])++trans =+    'transform'+        . 'fold' [ \"temp2017\", \"temp2018\" ]++enc =+    'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"key\", 'PmType' 'Graphics.Vega.VegaLite.Nominal' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"city\", 'PmType' 'Graphics.Vega.VegaLite.Nominal' ]+        . 'size' [ 'MName' \"value\", 'MmType' 'Graphics.Vega.VegaLite.Quantitative' ]+@++@since 0.4.0.0+-}++fold ::+  [FieldName]+  -- ^ The data fields to fold.+  -> BuildTransformSpecs+fold fields ols = TS (object [ "fold" .= fields ]) : ols+++{-|++A 'fold' where the @key@ and @value@ fields can be renamed.++@since 0.4.0.0++-}++foldAs ::+  [FieldName]+  -- ^ The data fields to fold.+  -> FieldName+  -- ^ The name for the @key@ field.+  -> FieldName+  -- ^ The name for the @value@ field.+  -> BuildTransformSpecs+foldAs fields keyName valName ols =+  let ofields = [ "fold" .= fields+                , "as" .= [ keyName, valName ]+                ]+  in TS (object ofields) : ols+++{-|++Perform a /pivot/ operation on a table. Spreads a key-value pair of fields+across multiple fields according to the data in the /key/ field.++It is the inverse of 'fold'.++@+dvals =+    'Graphics.Vega.VegaLite.dataFromColumns' []+        . 'Graphics.Vega.VegaLite.dataColumn' \"city\" ('Strings' [ \"Bristol\", \"Bristol\", \"Sheffield\", \"Sheffield\", \"Glasgow\", \"Glasgow\" ])+        . 'Graphics.Vega.VegaLite.dataColumn' \"temperature\" ('Numbers' [ 12, 14, 11, 13, 7, 10 ])+        . 'Graphics.Vega.VegaLite.dataColumn' \"year\" ('Numbers' [ 2017, 2018, 2017, 2018, 2017, 2018 ])++trans =+    'transform'+        . 'pivot' "year" "temperature" [ 'PiGroupBy' [ \"city\" ] ]++enc =+    'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"2017\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"city\", 'PmType' 'Graphics.Vega.VegaLite.Nominal' ]+@++@since 0.5.0.0+-}++pivot ::+  FieldName+  -- ^ The key field.+  -> FieldName+  -- ^ The value field.+  -> [PivotProperty]+  -> BuildTransformSpecs+pivot field valField pProps ols =+  let addField n p = case pivotPropertySpec p pProps of+                       A.Null -> []+                       x -> [n .= x]++      ofields = [ "pivot" .= field+                , "value" .= valField ]+                <> addField "groupby" PPLGroupBy+                <> addField "limit" PPLLimit+                <> addField "op" PPLOp++  in TS (object ofields) : ols+++{-|+Configure the 'pivot' operation.++@since 0.5.0.0+-}++data PivotProperty+  = PiGroupBy [FieldName]+    -- ^ The data fields to group by when pivoting. If unspecified+    --   then a single group containing all the data objects will+    --   be used.+  | PiLimit Natural+    -- ^ The maximum number of fields to generate when pivoting. If+    --   0 or unspecified all fields are pivoted. The pivot names+    --   are sorted into ascending order before the limit is+    --   applied.+  | PiOp Operation+    -- ^ The aggregation operation to apply to grouped fields.+++data PivotPropertyLabel = PPLGroupBy | PPLLimit | PPLOp++-- Multiple properties will lead to no output; in some ways+-- this makes sense (aka "you are telling me multiple things,+-- so I give up") and is used elsewhere.+--+-- TODO: this should return a Maybe VLSpec+pivotPropertySpec ::+  PivotPropertyLabel+  -> [PivotProperty]+  -> VLSpec+pivotPropertySpec PPLGroupBy ps =+  let wanted (PiGroupBy xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++pivotPropertySpec PPLLimit ps =+  let wanted (PiLimit xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> toJSON x+    _ -> A.Null++pivotPropertySpec PPLOp ps =+  let wanted (PiOp xs) = Just xs+      wanted _ = Nothing++  in case mapMaybe wanted ps of+    [x] -> operationSpec x+    _ -> A.Null+++{-|++Encode a URL for use with the 'Graphics.Vega.VegaLite.Image' mark type.++The URL can be encoded directly:++@+let axVals = 'Numbers' [ 0.5, 1.5, 2.5 ]++    dvals = 'Graphics.Vega.VegaLite.dataFromColumns' []+            . 'Graphics.Vega.VegaLite.dataColumn' "x" axVals+            . 'Graphics.Vega.VegaLite.dataColumn' "y" axVals++    enc = 'encoding'+          . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' "x", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+          . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' "y", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+          . 'url' [ 'HString' \"wonderful-image.png\" ]++    imMark = 'mark' 'Graphics.Vega.VegaLite.Image' [ 'Graphics.Vega.VegaLite.MWidth' 50, 'Graphics.Vega.VegaLite.MHeight' 25 ]++in 'Graphics.Vega.VegaLite.toVegaLite' [ dvals [], enc [], imMark ]+@++or by referencing a data field containing the URL values:++@+... 'Graphics.Vega.VegaLite.dataColumn' "img" ('Strings' [ \"i1.png\", \"i2.png\", \"i4.png\" ])++... 'url' [ 'HName' \"img\", 'HmType' 'Graphics.Vega.VegaLite.Nominal' ]+@++@since 0.5.0.0+-}++url :: [HyperlinkChannel] -> BuildEncodingSpecs+url hPs ols =+  ES ("url", object (concatMap hyperlinkChannelProperty hPs)) : ols+++{-|++Encode a hyperlink channel.++@+'encoding'+  . 'hyperlink' [ 'HName' \"Species\", 'HmType' 'Graphics.Vega.VegaLite.Nominal' ]+@++@+'encoding'+  . 'hyperlink' [ 'HString' \"http://www.imdb.com\" ]+@++For further details see the+<https://vega.github.io/vega-lite/docs/encoding.html#href Vega-Lite documentation>.++-}+hyperlink ::+  [HyperlinkChannel]+  -- ^ The properties for the hyperlink channel.+  -> BuildEncodingSpecs+hyperlink hyperProps ols =+  ES ("href", object (concatMap hyperlinkChannelProperty hyperProps)) : ols+++{-|++Perform a lookup of named fields between two data sources. This allows+you to find values in one data source based on the values in another+(like a relational join).++Use 'lookupSelection' for linking data with interactive selections.++See the <https://vega.github.io/vega-lite/docs/lookup.html Vega-Lite documentation>+for further details.++The following would return the values in the @age@ and @height@ fields from+@lookup_people.csv@ for all rows where the value in the @name@ column in that+file matches the value of @person@ in the primary data source.++@+peopleData = 'Graphics.Vega.VegaLite.dataFromUrl' \"data/lookup_people.csv\" []+lfields = 'LuFields' [\"age\", \"height\"]+trans = 'transform'+          . 'lookup' \"person\" peopleData \"name\" lfields+@++Note that the interface has changed in version @0.5.0.0@: the+output field names argument now uses the new 'LookupFields'+type. This provides greater flexibility in naming and+default behaviour. The conversion from version 0.4 is+simple: change++@+lookup key1 dataSource key2 fields+@++to++@+lookup key1 dataSource key2 (LuFields fields)+@++-}+lookup ::+  FieldName+  -- ^ The field in the primary data structure acting as the key.+  -> Data+  -- ^ The secondary data source (e.g. the return from the data-generating+  --   functions such as 'Graphics.Vega.VegaLite.dataFromUrl').+  -> FieldName+  -- ^ The name of the field in the secondary data source to match against+  --   the primary key.+  -> LookupFields+  -- ^ The list of fields to store when the keys match.+  --+  --   This was changed from @[T.Text]@ in vesion 0.5.0.0.+  -> BuildTransformSpecs+lookup key1 (_, spec) key2 lfields ols =+  let get1 = jj . map fst+      get2 = jj . map snd++      jj :: A.ToJSON a => a -> Maybe A.Value+      jj = Just . toJSON++      res = case lfields of               +             LuFields fs -> ( jj fs, Nothing, Nothing )+             LuFieldAs fas -> ( get1 fas, get2 fas, Nothing )+             LuAs s -> ( Nothing, jj s, Nothing )+             LuFieldsWithDefault fs def+               -> ( jj fs, Nothing , jj def )+             LuFieldsAsWithDefault fas def+               -> ( get1 fas, get2 fas, jj def )+             LuAsWithDefault s def -> ( Nothing, jj s, jj def )++      (mfields, mas, mdefault) = res++      addField n (Just x) = [ (n, x) ]+      addField _ _ = []++      fromFields = [ "data" .= spec+                   , "key" .= key2+                   ]+                   <> addField "fields" mfields++      ofields = [ "lookup" .= key1+                , "from" .= object fromFields+                ]+                <> addField "as" mas+                <> addField "default" mdefault++  in TS (object ofields) : ols+++{-|++Attach the results of an interactive selection to a primary data source.+This is similar to 'lookup' except that the data in a selection are used+in place of the secondary data source.++See the [Vega Lite lookup selection](https://vega.github.io/vega-lite/docs/lookup.html#lookup-selection) documentation.++@+sel = 'Graphics.Vega.VegaLite.selection'+      . 'Graphics.Vega.VegaLite.select' \"mySel\" 'Graphics.Vega.VegaLite.Single' [ 'Graphics.Vega.VegaLite.On' \"mouseover\", 'Graphics.Vega.VegaLite.Encodings' [ 'Graphics.Vega.VegaLite.ChX' ] ]++trans = 'transform'+        . 'lookupSelection' \"country\" \"mySel\" \"country\"+@++@since 0.5.0.0+-}++lookupSelection ::+  FieldName+  -- ^ The field to lookup in the primary data source.+  -> SelectionLabel+  -- ^ The name of the selection (as set with 'Graphics.Vega.VegaLite.select').+  -> FieldName+  -- ^ The name of the field in the selection to link with the+  --   primary data field.+  -> BuildTransformSpecs+lookupSelection key1 selName key2 ols =+  let ofields = [ "lookup" .= key1+                , "from" .= object [ "selection" .= selName+                                   , "key" .= key2 ]+                ]++  in TS (object ofields) : ols+++{-|+Configure the field selection in 'lookup'.++@since 0.5.0.0+-}+data LookupFields+  = LuFields [FieldName]+    -- ^ The name of the fields to return from the secondary data+    --   source.+  | LuFieldAs [(FieldName, FieldName)]+    -- ^ Select fields from the secondary data source (first+    --   argument) and allow them to be referred to with a+    --   new name (second argument).+  | LuAs FieldName+    -- ^ Create a single name for all the fields in the+    --   secondary data source. The individual fields use dot+    --   notation to combine the given name with the field name.+    --+    --   @+    --   dvals = 'Graphics.Vega.VegaLite.dataFromUrl' \"data/flights.airport.csv" []+    --   trans = 'transform'+    --           . 'lookup' \"origin\" dvals "iata" ('LuAs' \"o\")+    --   enc = 'encoding'+    --         . 'position' 'Graphics.Vega.VegaLite.Longitude' [ 'PName' \"o.longitude\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+    --         . 'position' 'Graphics.Vega.VegaLite.Lattude' [ 'PName' \"o.latitude\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+    --   @+  | LuFieldsWithDefault [FieldName] T.Text+    -- ^ The name of the fields to return from the secondary+    --   data source, along with the default value to use+    --   if the lookup fails.+  | LuFieldsAsWithDefault [(FieldName, FieldName)] T.Text+    -- ^ Allow fields to be renamed and provide a default for+    --   when the lookup fails.+  | LuAsWithDefault FieldName T.Text+    -- ^ Create a single name for all the fields in the+    --   secondary data source, but the second parameter+    --   gives the default value for when the lookup fails.+++{-|++This routine is deprecated (as of version @0.5.0.0@) in favor+of 'lookup', as++@+lookupAs "key1" dataSource "key2" "matchName"+@++can be written as++@+lookup "key1" dataSource "key2" (LuAs "matchName")+@++-}+{-# DEPRECATED lookupAs "Please change 'lookupAs ... alias' to 'lookup ... (LuAs alias)'" #-}+lookupAs ::+  FieldName+  -- ^ The field in the primary data structure acting as the key.+  -> Data+  -- ^ The secondary data source (e.g. the return from the data-generating+  --   functions such as 'Graphics.Vega.VegaLite.dataFromUrl').+  -> FieldName+  -- ^ The name of the field in the secondary data source to match against+  --   the primary key.+  -> FieldName+  -- ^ The field name for the new data.+  -> BuildTransformSpecs+lookupAs key1 sData key2 asName =+  lookup key1 sData key2 (LuAs asName)+++{-|++Impute missing data values.++The following example creates a value for @b@, set to the+mean of existing @b@ values with @c=1@, for the \"missing\" coordinate+of (@a=30@, @c=1@):++@+let dvals = 'Graphics.Vega.VegaLite.dataFromColumns' []+              . 'Graphics.Vega.VegaLite.dataColumn' "a" ('Numbers' [0, 0, 10, 10, 20, 20, 30])+              . 'Graphics.Vega.VegaLite.dataColumn' "b" ('Numbers' [28, 91, 43, 55, 81, 53, 19])+              . 'Graphics.Vega.VegaLite.dataColumn' "c" ('Numbers' [0, 1, 0, 1, 0, 1, 0])++    trans = 'transform'+              . 'impute' "b" "a" ['Graphics.Vega.VegaLite.ImMethod' 'Graphics.Vega.VegaLite.ImMean', 'Graphics.Vega.VegaLite.ImGroupBy' ["c"]]++    enc = 'encoding'+            . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"a\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+            . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"b\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative']+            . 'color' ['MName' \"c\", 'MmType' 'Graphics.Vega.VegaLite.Nominal']++    in 'Graphics.Vega.VegaLite.toVegaLite' [dvals [], trans [], enc [], 'mark' 'Graphics.Vega.VegaLite.Line' []]+@++@since 0.4.0.0+-}++impute ::+  FieldName+  -- ^ The data field to process.+  -> FieldName+  -- ^ The key field to uniquely identify data objects within a group.+  -> [ImputeProperty]+  -- ^ Define how the imputation works.+  -> BuildTransformSpecs+impute fields keyField imProps ols = imputeTS fields keyField imProps : ols+++{-|++Encode an opacity channel. The first parameter is a list of mark+channel properties that characterise the way a data field is encoded+by opacity. The second parameter is a list of any previous channels to+which this opacity channel should be added.++@+'opacity' [ 'MName' \"Age\", 'MmType' 'Graphics.Vega.VegaLite.Quantitative' ] []+@++See also 'fillOpacity'.++-}++opacity :: [MarkChannel] -> BuildEncodingSpecs+opacity markProps ols = mchan_ "opacity" markProps : ols+++{-|++Encode an order channel.++@+enc =+    'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' "miles", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' "gas", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'order' [ 'OName' "year", 'OmType' 'Graphics.Vega.VegaLite.Temporal', 'OSort' ['Descending'] ]+@+-}+order ::+  [OrderChannel]+  -- ^ The order-encoding options.+  -> BuildEncodingSpecs+order oDefs ols =+  ES ("order", object (map orderChannelProperty oDefs)) : ols+++{-|++Encode a position channel.++@+enc =+    'encoding'+      . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"Animal\", 'PmType' 'Graphics.Vega.VegaLite.Ordinal' ]+@++Encoding by position will generate an axis by default. To prevent the axis from+appearing, simply provide an empty list of axis properties to 'PAxis':++@+enc =+    'encoding'+      . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"Animal\", 'PmType' 'Graphics.Vega.VegaLite.Ordinal', 'PAxis' [] ]+@+-}+position ::+  Position+  -- ^ The channel to encode.+  -> [PositionChannel]+  -- ^ The options for the channel; this will usually include the name ('PName')+  --    and measurement type ('PmType'), but can be a reference to a row or+  --    column repeat field.+  -> BuildEncodingSpecs+position pos pDefs ols =+  let defs = object (map positionChannelProperty pDefs)+  in ES (positionLabel pos, defs) : ols+++{-|++Define a single resolution option to be applied when scales, axes or legends+in composite views share channel encodings. This allows, for example, two different+color encodings to be created in a layered view, which otherwise by default would+share color channels between layers. Each resolution rule should be in a tuple+pairing the channel to which it applies and the rule type.++@+'resolve'+    . resolution ('Graphics.Vega.VegaLite.RScale' [ ( 'Graphics.Vega.VegaLite.ChY', 'Graphics.Vega.VegaLite.Independent' ) ])+@+-}+resolution ::+  Resolve+  -> BuildResolveSpecs+  -- ^ Prior to @0.5.0.0@ this was @BuildLabelledSpecs@.+resolution res ols = resolveProperty res : ols+++{-|++Encode a new facet to be arranged in rows.++See the+<https://vega.github.io/vega-lite/docs/facet.html#facet-row-and-column-encoding-channels Vega-Lite row documentation>.++Note that when faceting, dimensions specified with 'width' and 'height'+refer to the individual faceted plots, not the whole visualization.++@+let dvals = 'Graphics.Vega.VegaLite.dataFromUrl' \"crimeData.csv\"+    enc = 'encoding'+            . 'position' 'Graphics.Vega.VegaLite.X' ['PName' \"month\", 'PmType' 'Graphics.Vega.VegaLite.Temporal']+            . 'position' 'Graphics.Vega.VegaLite.Y' ['PName' \"reportedCrimes\"+                         , 'PmType' 'Graphics.Vega.VegaLite.Quantitative'+                         , 'PAggregate' 'Graphics.Vega.VegaLite.Sum'+                         , 'PAxis' ['AxNoTitle']+                         ]+            . 'row' ['FName' \"crimeType\", 'FmType' 'Graphics.Vega.VegaLite.Nominal']++in 'Graphics.Vega.VegaLite.toVegaLite' ['height' 80, dvals [], 'mark' 'Graphics.Vega.VegaLite.Bar' [], enc []]+@++-}+row ::+  [FacetChannel]+  -- ^ The facet properties for the channel; this should include the name of+  --   the field ('FName') and its measurement type ('FmType').+  -> BuildEncodingSpecs+row fFields ols = ES ("row", object (map facetChannelProperty fFields)) : ols+++{-|++Encode a shape channel.++@+'shape' [ 'MName' \"Species\", 'MmType' 'Graphics.Vega.VegaLite.Nominal' ] []+@+-}+shape ::+  [MarkChannel]+  -- ^ What data values are used to control the shape parameters of the mark.+  -> BuildEncodingSpecs+shape markProps ols = mchan_ "shape" markProps : ols+++{-|++Encode a size channel.++@+'size' [ 'MName' \"Age\", 'MmType' 'Graphics.Vega.VegaLite.Quantitative' ] []+@+-}+size ::+  [MarkChannel]+  -- ^ What data values are used to control the size parameters of the mark.+  -> BuildEncodingSpecs+size markProps ols = mchan_ "size" markProps : ols+++{-|++Encode a stroke channel. This acts in a similar way to encoding by 'color' but+only affects the exterior boundary of marks.++@+'stroke' [ 'MName' \"Species\", 'MmType' 'Graphics.Vega.VegaLite.Nominal' ] []+@++Note that if both @stroke@ and 'color' encodings are specified, @stroke@ takes+precedence.++-}+stroke ::+  [MarkChannel]+  -- ^ What data values are used to control the stoke parameters of the mark.+  -> BuildEncodingSpecs+stroke markProps ols = mchan_ "stroke" markProps : ols+++{-|++Encode a stroke opacity channel. This acts in a similar way to encoding by+'opacity' but only affects the exterior boundary of marks. If both 'opacity' and+@strokeOpacity@ are specified, @strokeOpacity@ takes precedence for stroke encoding.++@since 0.4.0.0++-}++strokeOpacity ::+  [MarkChannel]+  -- ^ What data values are used to control the stoke opacity parameters of the mark.+  -> BuildEncodingSpecs+strokeOpacity markProps ols = mchan_ "strokeOpacity" markProps : ols+++{-|++Encode a stroke width channel.++@since 0.4.0.0++-}++strokeWidth ::+  [MarkChannel]+  -- ^ What data values are used to control the stoke width parameters of the mark.+  -> BuildEncodingSpecs+strokeWidth markProps ols = mchan_ "strokeWidth" markProps : ols+++{-|++Encode a text channel. See the+<https://vega.github.io/vega-lite/docs/encoding.html#text Vega-Lite documentation>+for further details on the text and tooltip channels and+<https://vega.github.io/vega-lite/docs/format.html Vega-Lite formatting documentation>+for formatting the appearance of the text.++@+'encoding'+    . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' "miles", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+    . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' "gas", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+    . 'text' [ 'TName' "miles", 'TmType' 'Graphics.Vega.VegaLite.Quantitative' ]+@+-}+text ::+  [TextChannel]+  -- ^ What data values are used to control the text parameters.+  -> BuildEncodingSpecs+text tDefs ols =+  ES ("text", object (concatMap textChannelProperty tDefs)) : ols+++{-|++Creates a new data field based on the given temporal binning. Unlike the+direct encoding binning, this transformation is named and so can be referred+to in multiple encodings. Note though that usually it is easer to apply the temporal+binning directly as part of the encoding as this will automatically format the+temporal axis. See the+<https://vega.github.io/vega-lite/docs/timeunit.html#transform Vega-Lite documentation>+for further details.++The following example takes a temporal dataset and encodes daily totals from it+grouping by month:++@+trans = 'transform' . 'timeUnitAs' 'Graphics.Vega.VegaLite.Month' \"date\" \"monthly\"++enc = 'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"date\", 'PmType' 'Graphics.Vega.VegaLite.Temporal', 'PTimeUnit' 'Graphics.Vega.VegaLite.Day' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PAggregate' 'Graphics.Vega.VegaLite.Sum', 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'detail' [ 'DName' \"monthly\", 'DmType' 'Graphics.Vega.VegaLite.Temporal' ]+@+-}+timeUnitAs ::+  TimeUnit+  -- ^ The width of each bin.+  -> FieldName+  -- ^ The field to bin.+  -> FieldName+  -- ^ The name of the binned data created by this routine.+  -> BuildTransformSpecs+timeUnitAs tu field label ols =+  let fields = [ "timeUnit" .= timeUnitLabel tu+               , "field" .= field+               , "as" .= label ]+  in TS (object fields) : ols+++{-|++Encode a tooltip channel. See the+<https://vega.github.io/vega-lite/docs/encoding.html#text Vega-Lite documentation>+for further details on the text and tooltip channels and+<https://vega.github.io/vega-lite/docs/format.html Vega-Lite formatting documentation>+for formatting the appearance of the text.++@+enc = 'encoding'+        . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"Horsepower\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"Miles_per_Gallon\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+        . 'tooltip' [ 'TName' \"Year\", 'TmType' 'Graphics.Vega.VegaLite.Temporal', 'TFormat' "%Y" ]+@++To encode multiple tooltip values with a mark, use 'tooltips'.++-}+tooltip ::+  [TextChannel]+  -- ^ The properties for the channel.+  --+  --   If the list is empty then this turns off tooltip support for+  --   this channel. This is new to @0.5.0.0@, but is also the+  --   default behavior in Vega Lite 4.+  -> BuildEncodingSpecs+tooltip [] ols =+  ES ("tooltip", A.Null) : ols+tooltip tDefs ols =+  ES ("tooltip", object (concatMap textChannelProperty tDefs)) : ols+++{-|++Encode a tooltip channel using multiple data fields.++@since 0.3.0.0++@+'encoding'+    . 'position' 'Graphics.Vega.VegaLite.X' [ 'PName' \"Horsepower\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+    . 'position' 'Graphics.Vega.VegaLite.Y' [ 'PName' \"Miles_per_Gallon\", 'PmType' 'Graphics.Vega.VegaLite.Quantitative' ]+    . 'tooltips' [ [ 'TName' \"Year\",  'TmType' 'Graphics.Vega.VegaLite.Temporal', 'TFormat' "%Y" ]+               , [ 'TName' \"Month\", 'TmType' 'Graphics.Vega.VegaLite.Temporal', 'TFormat' "%Y" ] ]+@+-}+tooltips ::+  [[TextChannel]]+  -- ^ A separate list of properties for each channel.+  -> BuildEncodingSpecs+tooltips tDefs ols =+  ES ("tooltip" .= map (object . concatMap textChannelProperty) tDefs) : ols
+ src/Graphics/Vega/VegaLite/Data.hs view
@@ -0,0 +1,100 @@+{-|+Module      : Graphics.Vega.VegaLite.Data+Copyright   : (c) Douglas Burke, 2018-2019+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable++Representing data values (excluding base time+types).++-}++module Graphics.Vega.VegaLite.Data+       ( DataValue(..)+       , DataValues(..)++       -- not for external export+       , dataValueSpec+       , dataValuesSpecs++       ) where++import qualified Data.Aeson as A+import qualified Data.Text as T++import Data.Aeson (object, toJSON)+++import Graphics.Vega.VegaLite.Specification (VLSpec)+import Graphics.Vega.VegaLite.Time+  ( DateTime+  , dateTimeProperty+  )+++{-|++A single data value. This is used when a function or constructor+can accept values of different types (e.g. either a number or a string),+such as:+'Graphics.Vega.VegaLite.dataRow', 'Graphics.Vega.VegaLite.geometry', many constructors of the 'Graphics.Vega.VegaLite.Filter' type,+'Graphics.Vega.VegaLite.ImNewValue', and 'Graphics.Vega.VegaLite.SInit'.++-}+data DataValue+    = Boolean Bool+    | DateTime [DateTime]+    | Number Double+    | Str T.Text+    | NullValue+      -- ^ Create a JavaScript @null@ value. This can be useful when+      --   explictly recoding a value as undefined, such as in the following+      --   example:+      --+      --   @+      --   'Graphics.Vega.VegaLite.dataFromRows' []+      --     . 'Graphics.Vega.VegaLite.dataRow' [("x", 'Number' 1), ("y", 'Str' "good")]+      --     . 'Graphics.Vega.VegaLite.dataRow' [("x", 'Number' 2), ("y", 'NullValue')]+      --     . 'Graphics.Vega.VegaLite.dataRow' [("x", 'Number' 3), ("y", 'String' "bad")]+      --   @+      --+      --   For more-complex data sources - such as lists of defined+      --   and un-specified values, it is suggested that 'Graphics.Vega.VegaLite.dataFromJson'+      --   be used rather than 'Graphics.Vega.VegaLite.dataFromRows' or 'Graphics.Vega.VegaLite.dataFromColumns'.+      --+      --   @since 0.4.0.0++dataValueSpec :: DataValue -> VLSpec+dataValueSpec (Boolean b) = toJSON b+dataValueSpec (DateTime dt) = object (map dateTimeProperty dt)+dataValueSpec (Number x) = toJSON x+dataValueSpec (Str t) = toJSON t+dataValueSpec NullValue = A.Null+++{-|++A list of data values. This is used when a function or constructor+can accept lists of different types (e.g. either a list of numbers+or a list of strings), such as:+'Graphics.Vega.VegaLite.dataColumn', 'Graphics.Vega.VegaLite.CustomSort', 'Graphics.Vega.VegaLite.FOneOf', or 'Graphics.Vega.VegaLite.ImKeyVals'.++If your data contains undefined values then it is suggested that+you convert it to JSON (e.g. 'A.Value') and then use 'Graphics.Vega.VegaLite.dataFromJson'.++-}+data DataValues+    = Booleans [Bool]+    | DateTimes [[DateTime]]+    | Numbers [Double]+    | Strings [T.Text]+++dataValuesSpecs :: DataValues -> [VLSpec]+dataValuesSpecs (Booleans bs) = map toJSON bs+dataValuesSpecs (DateTimes dtss) = map (object . map dateTimeProperty) dtss+dataValuesSpecs (Numbers xs) = map toJSON xs+dataValuesSpecs (Strings ss) = map toJSON ss+
+ src/Graphics/Vega/VegaLite/Foundation.hs view
@@ -0,0 +1,1512 @@+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Foundation+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : OverloadedStrings++Basic types that are used throughout VegaLite.+Would it make sense to break this up into+smaller modules?++-}++module Graphics.Vega.VegaLite.Foundation+       ( Angle+       , Color+       , DashStyle+       , DashOffset+       , FieldName+       , Opacity+       , VegaExpr+       , ZIndex++       , FontWeight(..)+       , Measurement(..)+       , Arrangement(..)+       , APosition(..)+       , Orientation(..)+       , Position(..)++       , HAlign(..)+       , VAlign(..)+       , BandAlign(..)++       , StrokeCap(..)+       , StrokeJoin(..)++       , Scale(..)++       , SortField(..)++       , Cursor(..)++       , OverlapStrategy(..)+       , Side(..)++       , Symbol(..)++       , StackProperty(..)+       , StackOffset(..)++       , TooltipContent(..)++       , Channel(..)+       , Resolve(..)+       , Resolution(..)++       , Bounds(..)+       , CompositionAlignment(..)+       , Padding(..)+       , Autosize(..)+       , RepeatFields(..)+       , CInterpolate(..)++       , ViewBackground(..)++       , HeaderProperty(..)++       -- not for external export+       , fontWeightSpec+       , measurementLabel+       , arrangementLabel+       , anchorLabel+       , orientationSpec+       , hAlignLabel+       , vAlignLabel+       , bandAlignLabel+       , strokeCapLabel+       , strokeJoinLabel+       , scaleLabel+       , positionLabel+       , sortFieldSpec+       , cursorLabel+       , overlapStrategyLabel+       , sideLabel+       , symbolLabel+       , stackPropertySpecSort+       , stackPropertySpecOffset+       , stackOffset+       , ttContentLabel+       , channelLabel+       , resolveProperty+       , boundsSpec+       , compositionAlignmentSpec+       , paddingSpec+       , autosizeProperty+       , repeatFieldsProperty+       , cInterpolateSpec+       , viewBackgroundSpec++       , fromT+       , fromColor+       , fromDS+       , splitOnNewline+       , field_+       , header_+       , order_+       , allowNull+       )+    where++import qualified Data.Aeson as A+import qualified Data.Text as T++import Data.Aeson ((.=), object, toJSON)+++-- added in base 4.8.0.0 / ghc 7.10.1+import Numeric.Natural (Natural)+++import Graphics.Vega.VegaLite.Specification+  ( VLSpec+  , LabelledSpec+  , ResolveSpec(..)+  )+++field_ :: FieldName -> LabelledSpec+field_ f = "field" .= f++header_ :: [HeaderProperty] -> LabelledSpec+header_ hps = "header" .= object (map headerProperty hps)++-- could restrict to ascending/descending+order_ :: T.Text -> LabelledSpec+order_ o = "order" .= o+++-- allowNull :: A.ToJSON a => Maybe a -> VLSpec+allowNull :: Maybe Int -> VLSpec+allowNull (Just a) = toJSON a+allowNull Nothing = A.Null+++{-|++The field name. This can include \"dotted\" notation, such as+@\"o.latitude\"@.++There is __no attempt__ to validate this value (e.g. check it+is not empty, contains only valid characters, or+remove excess whitespace).++@since 0.5.0.0+-}+type FieldName = T.Text+++{-|++Convenience type-annotation label to indicate a color value.+There is __no attempt__ to validate that the user-supplied input+is a valid color.++Any supported HTML color specification can be used, such as:++@+\"#eee\"+\"#734FD8\"+\"crimson\"+\"rgb(255,204,210)\"+\"hsl(180, 50%, 50%)\"+@++A blank string is converted to the JSON null value (new in @0.5.0.0@).++@since 0.4.0.0+-}++type Color = T.Text+++-- strip out trailing white space just to be sure+fromColor :: Color -> VLSpec+fromColor = cleanT+++-- strips leading and trailing white space and, if the result+-- is empty, returns Null, otherwise the trimmed text.+--+cleanT :: T.Text -> VLSpec+cleanT t =+  let tout = T.strip t+  in if T.null tout+     then A.Null+     else toJSON tout++++{-|+The dash style for a line. This is defined as a series of on and then+off lengths, in pixels. So @[10, 4, 5, 2]@ means a long line, followed+by a space, then a line half as long as the first segment, and then+a short space. This pattern is then repeated.++This is a convenience type annotation and there is __no validation__+of the input.++@since 0.5.0.0+-}+type DashStyle = [Double]+++fromDS :: DashStyle -> VLSpec+-- fromDS [] = A.Null  -- what is the correct handling of this?+fromDS = toJSON+++{-|+The offset at which to start drawing the line dash (given by a+'DashStyle' argument), in pixels.++This is a convenience type annotation and there is __no validation__+of the input.++@since 0.5.0.0+-}+type DashOffset = Double+++{-|++Convenience type-annotation label to indicate an opacity value, which+lies in the range 0 to 1 inclusive. There is __no attempt__ to validate+that the user-supplied value falls in this range.++A value of 0 indicates fully transparent (see through), and 1 is+fully opaque (does not show anything it is on top of).++@since 0.4.0.0+-}++type Opacity = Double+++{-|++Convenience type-annotation label to indicate an angle, which is measured+in degrees from the horizontal (so anti-clockwise).++The value should be in the range 0 to 360, inclusive, but __no attempt__ is+made to enforce this.++@since 0.4.0.0+-}++type Angle = Double+++{-|++At what "depth" (z index) is the item to be drawn (a relative depth+for items in the visualization). The standard values are @0@ for+back and @1@ for front, but other values can be used if you want+to ensure a certain layering of items.++The following example is taken from a discussion with+<https://github.com/gicentre/elm-vegalite/issues/15#issuecomment-524527125 Jo Wood>:++@+let dcols = 'Graphics.Vega.VegaLite.dataFromColumns' []+              . 'Graphics.Vega.VegaLite.dataColumn' "x" ('Graphics.Vega.VegaLite.Numbers' [ 20, 10 ])+              . 'Graphics.Vega.VegaLite.dataColumn' "y" ('Graphics.Vega.VegaLite.Numbers' [ 10, 20 ])+              . 'Graphics.Vega.VegaLite.dataColumn' "cat" ('Graphics.Vega.VegaLite.Strings' [ "a", "b" ])++    axis lbl z = [ 'Graphics.Vega.VegaLite.PName' lbl, 'Graphics.Vega.VegaLite.PmType' 'Graphics.Vega.VegaLite.Quantitative', 'Graphics.Vega.VegaLite.PAxis' [ 'Graphics.Vega.VegaLite.AxZIndex' z ] ]+    enc = 'Graphics.Vega.VegaLite.encoding'+            . 'Graphics.Vega.VegaLite.position' 'X' (axis "x" 2)+            . 'Graphics.Vega.VegaLite.position' 'Y' (axis "y" 1)+            . 'Graphics.Vega.VegaLite.color' [ 'Graphics.Vega.VegaLite.MName' "cat", 'Graphics.Vega.VegaLite.MmType' 'Graphics.Vega.VegaLite.Nominal', 'Graphics.Vega.VegaLite.MLegend' [] ]++    cfg = 'Graphics.Vega.VegaLite.configure'+            . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.Axis' [ 'Graphics.Vega.VegaLite.GridWidth' 8 ])+            . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.AxisX' [ 'Graphics.Vega.VegaLite.GridColor' "red" ])+            . 'Graphics.Vega.VegaLite.configuration' ('Graphics.Vega.VegaLite.AxisY' [ 'Graphics.Vega.VegaLite.GridColor' "blue" ])++in 'Graphics.Vega.VegaLite.toVegaLite' [ cfg []+              , dcols []+              , enc []+              , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Circle' [ 'Graphics.Vega.VegaLite.MSize' 5000, 'Graphics.Vega.VegaLite.MOpacity' 1 ]+              ]+@++<<images/zindex.png>>++<https://vega.github.io/editor/#/url/vega-lite/N4KABBYEQMYPYDsBmBLA5lAXGUk-QEMAPFAZwE0sdx9ao0AnFAEwGE4AbOBqqAIw4BXAKZQatAL4AacfijEyADSq5acxi3Zce2KA2HMxasNNl55JUirNr6TZgHUWAFwAWVABw2IE2afMAtgQMANbWxlCkKABeotgArAAMyTIRcAAOBDAozgCeVACMqbZ56XHQ2QwwHKJ+xRBQzATOBOG2AG4EQsJW2ADa3viqxnQwzbyt9SPmRFQATIlT0w352AWJg3j+y8PLDWPOvHxQS8tQs2uLm7arYAvXPoMAunWyUAAkpDCuwkG8rs5nOlSJgAPSg9rCNAEAB0aByrkEfBhKDgoK+PyCEKhBAAtBwcsIIQBmGEAK1IiBOb2ECHgzBQCAw2F25ng2ja0ygqGEHEMugO1L2UFK5SgCDgAUZXSFZxqaFp-LACEEHA4g22dAu1GFPL5vFmpzoot4AEdBAQEM4cs0UJDZVyFL0dXtIFBoozmMJtXMHiYNUboLdWbY9UqoPlA+YTbpzZbrS1rfao26nZzXe7Pd7Cn7fMY85BfL4gA View the visualization in the Vega Editor>++@since 0.4.0.0+-}++type ZIndex = Natural+++{-|++Convenience type-annotation label to indicate a+<https://vega.github.io/vega/docs/expressions/ Vega Expression>.+There is __no attempt__ to validate the expression.++Examples include:++@+"datum.IMDB_Rating != null"+"datum.height / 1000"+"if(datum.index % 2 == 1, datum.label, '')"+"sampleLogNormal(2.3, 0.3)"+@++@since 0.5.0.0+-}+type VegaExpr = T.Text+++-- | Indicates the weight options for a font.++data FontWeight+    = Bold+    | Bolder+    | Lighter+    | Normal+    | W100+    | W200+    | W300+    | W400+    | W500+    | W600+    | W700+    | W800+    | W900+++fromF :: Double -> VLSpec+fromF = toJSON++fromT :: T.Text -> VLSpec+fromT = toJSON++-- If there is a new-line in the text then convert to a list.+splitOnNewline :: T.Text -> VLSpec+splitOnNewline ts =+  case T.split (== '\n') ts of+    [] -> fromT ""+    [s] -> toJSON s+    s -> toJSON s+++fontWeightSpec :: FontWeight -> VLSpec+fontWeightSpec Bold = fromT "bold"+fontWeightSpec Bolder = fromT "bolder"+fontWeightSpec Lighter = fromT "lighter"+fontWeightSpec Normal = fromT "normal"+fontWeightSpec W100 = fromF 100+fontWeightSpec W200 = fromF 200+fontWeightSpec W300 = fromF 300+fontWeightSpec W400 = fromF 400+fontWeightSpec W500 = fromF 500+fontWeightSpec W600 = fromF 600+fontWeightSpec W700 = fromF 700+fontWeightSpec W800 = fromF 800+fontWeightSpec W900 = fromF 900+++{-|++Type of measurement to be associated with some channel.++-}++data Measurement+    = Nominal+      -- ^ Data are categories identified by name alone and which have no intrinsic order.+    | Ordinal+      -- ^ Data are also categories, but ones which have some natural order.+    | Quantitative+      -- ^ Data are numeric measurements typically on a continuous scale.+    | Temporal+      -- ^ Data represents time in some manner.+    | GeoFeature+      -- ^ Geospatial position encoding ('Longitude' and 'Latitude') should specify the 'Graphics.Vega.VegaLite.PmType'+      -- as @Quantitative@. Geographically referenced features encoded as 'Graphics.Vega.VegaLite.shape' marks+      -- should specify 'Graphics.Vega.VegaLite.MmType' as @GeoFeature@ (Vega-Lite currently refers to this type+      -- as @<https://vega.github.io/vega-lite/docs/encoding.html geojson>@.+++measurementLabel :: Measurement -> T.Text+measurementLabel Nominal = "nominal"+measurementLabel Ordinal = "ordinal"+measurementLabel Quantitative = "quantitative"+measurementLabel Temporal = "temporal"+measurementLabel GeoFeature = "geojson"+++-- | Identifies how repeated or faceted views are arranged.+--+--   This is used with a number of constructors: 'Graphics.Vega.VegaLite.ByRepeatOp',+--   'Graphics.Vega.VegaLite.HRepeat', 'Graphics.Vega.VegaLite.MRepeat', 'Graphics.Vega.VegaLite.ORepeat', 'Graphics.Vega.VegaLite.PRepeat', and 'Graphics.Vega.VegaLite.TRepeat'.++-- based on schema 3.3.0 #/definitions/RepeatRef++data Arrangement+    = Column+      -- ^ Column arrangement.+    | Row+      -- ^ Row arrangement.+    | Flow+      -- ^ Flow arrangement (aka \"repeat\").+      --+      --   @since 0.4.0.0+++arrangementLabel :: Arrangement -> T.Text+arrangementLabel Column = "column"+arrangementLabel Row = "row"+arrangementLabel Flow = "repeat"  -- NOTE: not "flow"!+++-- | Indicates the anchor position for text.++data APosition+    = AStart+      -- ^ The start of the text.+    | AMiddle+      -- ^ The middle of the text.+    | AEnd+      -- ^ The end of the text.+++anchorLabel :: APosition -> T.Text+anchorLabel AStart = "start"+anchorLabel AMiddle = "middle"+anchorLabel AEnd = "end"+++{-|++The orientation of an item. This is used with:+'Graphics.Vega.VegaLite.BLeLDirection', 'Graphics.Vega.VegaLite.LDirection',+'Graphics.Vega.VegaLite.LeGradientDirection', 'Graphics.Vega.VegaLite.LeLDirection', 'Graphics.Vega.VegaLite.LeSymbolDirection',+and 'Graphics.Vega.VegaLite.MOrient'.++In @0.4.0.0@ this was renamed from @MarkOrientation@ to 'Orientation'.++-}++-- based on schema 3.3.0 #/definitions/Orientation++data Orientation+    = Horizontal+      -- ^ Display horizontally.+    | Vertical+      -- ^ Display vertically.+++orientationSpec :: Orientation -> VLSpec+orientationSpec Horizontal = "horizontal"+orientationSpec Vertical = "vertical"+++-- TODO:+--+--  encoding of X2/... shouldn't include the PmType in the output, apparently+--  so we could try and filter that out, or just rely on the user to not+--  add the PmType fields in this case.++{-|++Type of position channel, @X@ and @Y@ represent horizontal and vertical axis+dimensions on a plane and @X2@ and @Y2@ represent secondary axis dimensions where+two scales are overlaid in the same space. Geographic positions represented by+longitude and latiutude values are identified with @Longitude@, @Latitude@ and+their respective secondary equivalents. Such geographic position channels are+subject to a map projection (set using 'Graphics.Vega.VegaLite.projection') before being placed graphically.++-}+data Position+    = X+    | Y+    | X2+    -- ^ The secondary coordinate for ranged 'Graphics.Vega.VegaLite.Area', 'Graphics.Vega.VegaLite.Bar', 'Graphics.Vega.VegaLite.Rect', and 'Graphics.Vega.VegaLite.Rule'+    --    marks.+    | Y2+    -- ^ The secondary coordinate for ranged 'Graphics.Vega.VegaLite.Area', 'Graphics.Vega.VegaLite.Bar', 'Graphics.Vega.VegaLite.Rect', and 'Graphics.Vega.VegaLite.Rule'+    --    marks.+    | XError+      -- ^ Indicates that the 'X' channel represents the mid-point and+      --   the 'XError' channel gives the offset. If 'XError2' is not+      --   defined then this channel value is applied symmetrically.+      --+      --   @since 0.4.0.0+    | XError2+      -- ^ Used to support asymmetric error ranges defined as 'XError'+      --   and 'XError2'. One of 'XError' or 'XError2' channels must+      --   contain positive values and the other negative values.+      --+      --   @since 0.4.0.0+    | YError+      -- ^ Indicates that the 'Y' channel represents the mid-point and+      --   the 'YError' channel gives the offset. If 'YError2' is not+      --   defined then this channel value is applied symmetrically.+      --+      --   @since 0.4.0.0+    | YError2+      -- ^ Used to support asymmetric error ranges defined as 'YError'+      --   and 'YError2'. One of 'YError' or 'YError2' channels must+      --   contain positive values and the other negative values.+      --+      --   @since 0.4.0.0+    | Longitude+      -- ^ The longitude value for projections.+    | Latitude+      -- ^ The latitude value for projections.+    | Longitude2+      -- ^ A second longitude coordinate.+    | Latitude2+      -- ^ A second longitude coordinate.+++positionLabel :: Position -> T.Text+positionLabel X = "x"+positionLabel Y = "y"+positionLabel X2 = "x2"+positionLabel Y2 = "y2"+positionLabel XError     = "xError"+positionLabel YError     = "yError"+positionLabel XError2    = "xError2"+positionLabel YError2    = "yError2"+positionLabel Longitude = "longitude"+positionLabel Latitude = "latitude"+positionLabel Longitude2 = "longitude2"+positionLabel Latitude2 = "latitude2"++++-- | Indicates the horizontal alignment of text such as on an axis or legend.++data HAlign+    = AlignCenter+    | AlignLeft+    | AlignRight+++-- | Indicates the vertical alignment of text that may be attached to a mark.++data VAlign+    = AlignTop+    | AlignMiddle+    | AlignBottom+++hAlignLabel :: HAlign -> T.Text+hAlignLabel AlignLeft = "left"+hAlignLabel AlignCenter = "center"+hAlignLabel AlignRight = "right"+++vAlignLabel :: VAlign -> T.Text+vAlignLabel AlignTop = "top"+vAlignLabel AlignMiddle = "middle"+vAlignLabel AlignBottom = "bottom"+++{-|++Where should tick marks and grid lines be placed. This is used with+'Graphics.Vega.VegaLite.AxTickBand' and 'Graphics.Vega.VegaLite.TickBand'.++@since 0.5.0.0+-}++data BandAlign+  = BCenter+    -- ^ Use the center of the band.+  | BExtent+    -- ^ Use the band extents.+++bandAlignLabel :: BandAlign -> T.Text+bandAlignLabel BCenter = "center"+bandAlignLabel BExtent = "extent"+++-- | How are strokes capped? This is used with 'Graphics.Vega.VegaLite.MStrokeCap', 'Graphics.Vega.VegaLite.VBStrokeCap',+--   and 'Graphics.Vega.VegaLite.ViewStrokeCap'.+--+--   @since 0.4.0.0++data StrokeCap+    = CButt+      -- ^ Butt stroke cap.+    | CRound+      -- ^ Rounded stroke cap.+    | CSquare+      -- ^ Square stroke cap.+++strokeCapLabel :: StrokeCap -> T.Text+strokeCapLabel CButt = "butt"+strokeCapLabel CRound = "round"+strokeCapLabel CSquare = "square"+++-- | How are strokes joined? This is used with 'Graphics.Vega.VegaLite.MStrokeJoin', 'Graphics.Vega.VegaLite.VBStrokeJoin',+--   and 'Graphics.Vega.VegaLite.ViewStrokeJoin'.+--+--+--   @since 0.4.0.0++data StrokeJoin+    = JMiter+      -- ^ Mitred stroke join.+    | JRound+      -- ^ Rounded stroke join.+    | JBevel+      -- ^ Bevelled stroke join.+++strokeJoinLabel :: StrokeJoin -> T.Text+strokeJoinLabel JMiter = "miter"+strokeJoinLabel JRound = "round"+strokeJoinLabel JBevel = "bevel"+++-- | Used to indicate the type of scale transformation to apply.+--+--   The @0.4.0.0@ release removed the @ScSequential@ constructor, as+--   'ScLinear' should be used instead.++data Scale+    = ScLinear+      -- ^ A linear scale.+    | ScPow+      -- ^ A power scale. The exponent to use for scaling is specified with+      --   'Graphics.Vega.VegaLite.SExponent'.+    | ScSqrt+      -- ^ A square-root scale.+    | ScLog+      -- ^ A log scale. Defaults to log of base 10, but can be customised with+      --   'Graphics.Vega.VegaLite.SBase'.+    | ScSymLog+      -- ^ A [symmetrical log (PDF link)](https://www.researchgate.net/profile/John_Webber4/publication/233967063_A_bi-symmetric_log_transformation_for_wide-range_data/links/0fcfd50d791c85082e000000.pdf)+      --   scale. Similar to a log scale but supports zero and negative values. The slope+      --   of the function at zero can be set with 'Graphics.Vega.VegaLite.SConstant'.+      --+      --   @since 0.4.0.0+    | ScTime+      -- ^ A temporal scale.+    | ScUtc+      -- ^ A temporal scale, in UTC.+    | ScOrdinal+      -- ^ An ordinal scale.+    | ScBand+      -- ^ A band scale.+    | ScPoint+      -- ^ A point scale.+    | ScBinLinear+      -- ^ A linear band scale.+    | ScBinOrdinal+      -- ^ An ordinal band scale.+    | ScQuantile+      -- ^ A quantile scale.+      --+      --   @since 0.4.0.0+    | ScQuantize+      -- ^ A quantizing scale.+      --+      --   @since 0.4.0.0+    | ScThreshold+      -- ^ A threshold scale.+      --+      --   @since 0.4.0.0+++scaleLabel :: Scale -> T.Text+scaleLabel ScLinear = "linear"+scaleLabel ScPow = "pow"+scaleLabel ScSqrt = "sqrt"+scaleLabel ScLog = "log"+scaleLabel ScSymLog = "symlog"+scaleLabel ScTime = "time"+scaleLabel ScUtc = "utc"+scaleLabel ScOrdinal = "ordinal"+scaleLabel ScBand = "band"+scaleLabel ScPoint = "point"+scaleLabel ScBinLinear = "bin-linear"+scaleLabel ScBinOrdinal = "bin-ordinal"+scaleLabel ScQuantile = "quantile"+scaleLabel ScQuantize = "quantize"+scaleLabel ScThreshold = "threshold"+++-- | How should the field be sorted when performing a window transform.+--+--   @since 0.4.00++data SortField+    = WAscending FieldName+    -- ^ Sort the field into ascending order.+    | WDescending FieldName+    -- ^ Sort the field into descending order.+++sortFieldSpec :: SortField -> VLSpec+sortFieldSpec (WAscending f) = object [field_ f, order_ "ascending"]+sortFieldSpec (WDescending f) = object [field_ f, order_ "descending"]+++{-|++Represents the type of cursor to display. For an explanation of each type,+see the+<https://developer.mozilla.org/en-US/docs/Web/CSS/cursor#Keyword%20values CSS documentation>.++-}+data Cursor+    = CAuto+    | CDefault+    | CNone+    | CContextMenu+    | CHelp+    | CPointer+    | CProgress+    | CWait+    | CCell+    | CCrosshair+    | CText+    | CVerticalText+    | CAlias+    | CCopy+    | CMove+    | CNoDrop+    | CNotAllowed+    | CAllScroll+    | CColResize+    | CRowResize+    | CNResize+    | CEResize+    | CSResize+    | CWResize+    | CNEResize+    | CNWResize+    | CSEResize+    | CSWResize+    | CEWResize+    | CNSResize+    | CNESWResize+    | CNWSEResize+    | CZoomIn+    | CZoomOut+    | CGrab+    | CGrabbing+++cursorLabel :: Cursor -> T.Text+cursorLabel CAuto = "auto"+cursorLabel CDefault = "default"+cursorLabel CNone = "none"+cursorLabel CContextMenu = "context-menu"+cursorLabel CHelp = "help"+cursorLabel CPointer = "pointer"+cursorLabel CProgress = "progress"+cursorLabel CWait = "wait"+cursorLabel CCell = "cell"+cursorLabel CCrosshair = "crosshair"+cursorLabel CText = "text"+cursorLabel CVerticalText = "vertical-text"+cursorLabel CAlias = "alias"+cursorLabel CCopy = "copy"+cursorLabel CMove = "move"+cursorLabel CNoDrop = "no-drop"+cursorLabel CNotAllowed = "not-allowed"+cursorLabel CAllScroll = "all-scroll"+cursorLabel CColResize = "col-resize"+cursorLabel CRowResize = "row-resize"+cursorLabel CNResize = "n-resize"+cursorLabel CEResize = "e-resize"+cursorLabel CSResize = "s-resize"+cursorLabel CWResize = "w-resize"+cursorLabel CNEResize = "ne-resize"+cursorLabel CNWResize = "nw-resize"+cursorLabel CSEResize = "se-resize"+cursorLabel CSWResize = "sw-resize"+cursorLabel CEWResize = "ew-resize"+cursorLabel CNSResize = "ns-resize"+cursorLabel CNESWResize = "nesw-resize"+cursorLabel CNWSEResize = "nwse-resize"+cursorLabel CZoomIn = "zoom-in"+cursorLabel CZoomOut = "zoom-out"+cursorLabel CGrab = "grab"+cursorLabel CGrabbing = "grabbing"+++{-|++Type of overlap strategy to be applied when there is not space to show all items+on an axis, and is used by+'Graphics.Vega.VegaLite.AxLabelOverlap',+'Graphics.Vega.VegaLite.LabelOverlap',+'Graphics.Vega.VegaLite.LLabelOverlap',+and 'Graphics.Vega.VegaLite.LeLabelOverlap'.+See the+<https://vega.github.io/vega-lite/docs/axis.html#labels Vega-Lite documentation>+for more details.+-}++data OverlapStrategy+    = ONone+      -- ^ No overlap strategy to be applied when there is not space to show all items+      --   on an axis.+    | OParity+      -- ^ Give all items equal weight in overlap strategy to be applied when there is+      --   not space to show them all on an axis.+    | OGreedy+      -- ^ Greedy overlap strategy to be applied when there is not space to show all+      --   items on an axis.++overlapStrategyLabel :: OverlapStrategy -> VLSpec+overlapStrategyLabel ONone = toJSON False+overlapStrategyLabel OParity = toJSON True  -- fromT "parity"+overlapStrategyLabel OGreedy = fromT "greedy"+++{-|++Represents one side of a rectangular space.++Used by+'Graphics.Vega.VegaLite.AxOrient',+'Graphics.Vega.VegaLite.HLabelOrient',+'Graphics.Vega.VegaLite.HTitleOrient',+'Graphics.Vega.VegaLite.LTitleOrient',+'Graphics.Vega.VegaLite.LeTitleOrient',+'Graphics.Vega.VegaLite.Orient',+and+'Graphics.Vega.VegaLite.TOrient'.++-}++data Side+    = STop+    | SBottom+    | SLeft+    | SRight+++sideLabel :: Side -> T.Text+sideLabel STop = "top"+sideLabel SBottom = "bottom"+sideLabel SLeft = "left"+sideLabel SRight = "right"+++-- | Identifies the type of symbol used with the 'Graphics.Vega.VegaLite.Point' mark type.+--   It is used with 'Graphics.Vega.VegaLite.MShape', 'Graphics.Vega.VegaLite.LeSymbolType', and 'Graphics.Vega.VegaLite.LSymbolType'.+--+--   In version @0.4.0.0@ all constructors were changed to start+--   with @Sym@.+--+data Symbol+    = SymCircle+      -- ^ Specify a circular symbol for a shape mark.+    | SymSquare+      -- ^ Specify a square symbol for a shape mark.+    | SymCross+      -- ^ Specify a cross symbol for a shape mark.+    | SymDiamond+      -- ^ Specify a diamond symbol for a shape mark.+    | SymTriangleUp+      -- ^ Specify an upward-triangular symbol for a shape mark.+    | SymTriangleDown+      -- ^ Specify a downward-triangular symbol for a shape mark.+    | SymTriangleRight+      -- ^ Specify an right-facing triangular symbol for a shape mark.+      --+      --   @since 0.4.0.0+    | SymTriangleLeft+      -- ^ Specify an left-facing triangular symbol for a shape mark.+      --+      --   @since 0.4.0.0+    | SymStroke+      -- ^ The line symbol.+      --+      --  @since 0.4.0.0+    | SymArrow+      -- ^ Centered directional shape.+      --+      --  @since 0.4.0.0+    | SymTriangle+      -- ^ Centered directional shape. It is not clear what difference+      --   this is to 'SymTriangleUp'.+      --+      --  @since 0.4.0.0+    | SymWedge+      -- ^ Centered directional shape.+      --+      --  @since 0.4.0.0+    | SymPath T.Text+      -- ^ A custom symbol shape as an+      --   [SVG path description](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths).+      --+      --   For correct sizing, the path should be defined within a square+      --   bounding box, defined on an axis of -1 to 1 for both dimensions.+++symbolLabel :: Symbol -> T.Text+symbolLabel SymCircle = "circle"+symbolLabel SymSquare = "square"+symbolLabel SymCross = "cross"+symbolLabel SymDiamond = "diamond"+symbolLabel SymTriangleUp = "triangle-up"+symbolLabel SymTriangleDown = "triangle-down"+symbolLabel SymTriangleRight = "triangle-right"+symbolLabel SymTriangleLeft = "triangle-left"+symbolLabel SymStroke = "stroke"+symbolLabel SymArrow = "arrow"+symbolLabel SymTriangle = "triangle"+symbolLabel SymWedge = "wedge"+symbolLabel (SymPath svgPath) = svgPath+++-- | How are stacks applied within a transform?+--+--   Prior to version @0.4.0.0@ the @StackProperty@ type was+--   what is now @StackOffset@.++data StackProperty+    = StOffset StackOffset+      -- ^ Stack offset.+      --+      --   @since 0.4.0.0+    | StSort [SortField]+      -- ^ Ordering within a stack.+      --+      --   @since 0.4.0.0+++-- | Describes the type of stacking to apply to a bar chart.+--+--   In @0.4.0.0@ this was renamed from @StackProperty@ to @StackOffset@,+--   but the constructor names have not changed.+--+data StackOffset+    = StZero+      -- ^ Offset a stacked layout using a baseline at the foot of+      --   the stack.+    | StNormalize+      -- ^ Rescale a stacked layout to use a common height while+      --   preserving the relative size of stacked quantities.+    | StCenter+      -- ^ Offset a stacked layout using a central stack baseline.+    | NoStack+      -- ^ Do not stack marks, but create a layered plot.++stackOffsetSpec :: StackOffset -> VLSpec+stackOffsetSpec StZero = "zero"+stackOffsetSpec StNormalize = "normalize"+stackOffsetSpec StCenter = "center"+stackOffsetSpec NoStack = A.Null++stackOffset :: StackOffset -> LabelledSpec+stackOffset so = "stack" .= stackOffsetSpec so+++stackPropertySpecOffset , stackPropertySpecSort:: StackProperty -> Maybe VLSpec+stackPropertySpecOffset (StOffset op) = Just (stackOffsetSpec op)+stackPropertySpecOffset _ = Nothing++stackPropertySpecSort (StSort sfs) = Just (toJSON (map sortFieldSpec sfs))+stackPropertySpecSort _ = Nothing+++-- | This is used with 'Graphics.Vega.VegaLite.MTooltip' and+--   can be used with 'Graphics.Vega.VegaLite.mark' or+--   'Graphics.Vega.VegaLite.MarkStyle'.+--+--   @since 0.4.0.0++data TooltipContent+  = TTEncoding+    -- ^ When enabled, tooltips are generated by the encoding+    --   (this is the default).+    --+    --   For example:+    --+    --   @'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Circle' ['Graphics.Vega.VegaLite.MTooltip' 'TTEncoding']@+  | TTData+    -- ^ Tooltips are generated by all fields in the underlying data.+    --+    --   For example:+    --+    --   @'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Circle' ['Graphics.Vega.VegaLite.MTooltip' 'TTData']@+  | TTNone+    -- ^ Disable tooltips. This is the default behavior in Vega-Lite 4,+    --   and can also be achieved by adding an encoding of+    --   @'Graphics.Vega.VegaLite.tooltip' []@.+    --+    --   For example:+    --+    --   @'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Circle' ['Graphics.Vega.VegaLite.MTooltip' 'TTNone']@+++-- Note that TTNone is special cased by markProperty+ttContentLabel :: TooltipContent -> T.Text+ttContentLabel TTEncoding = "encoding"+ttContentLabel TTData = "data"+ttContentLabel TTNone = "null"+++-- | Indicates a channel type to be used in a resolution specification.++-- assuming this is based on schema 3.3.0 #/definitions/SingleDefUnitChannel++data Channel+    = ChX+    | ChY+    | ChX2+    | ChY2+    | ChLongitude+      -- ^ @since 0.4.0.0+    | ChLongitude2+      -- ^ @since 0.4.0.0+    | ChLatitude+      -- ^ @since 0.4.0.0+    | ChLatitude2+      -- ^ @since 0.4.0.0+    | ChColor+    | ChFill+      -- ^ @since 0.3.0.0+    | ChFillOpacity+      -- ^ @since 0.4.0.0+    | ChHref+      -- ^ @since 0.4.0.0+    | ChKey+      -- ^ @since 0.4.0.0+    | ChStroke+      -- ^ @since 0.3.0.0+    | ChStrokeOpacity+      -- ^ @since 0.4.0.0+    | ChStrokeWidth+      -- ^ @since 0.4.0.0+    | ChOpacity+    | ChShape+    | ChSize+    | ChText+      -- ^ @since 0.4.0.0+    | ChTooltip+      -- ^ @since 0.4.0.0+++channelLabel :: Channel -> T.Text+channelLabel ChX = "x"+channelLabel ChY = "y"+channelLabel ChX2 = "x2"+channelLabel ChY2 = "y2"+channelLabel ChLongitude = "longitude"+channelLabel ChLatitude = "latitude"+channelLabel ChLongitude2 = "longitude2"+channelLabel ChLatitude2 = "latitude2"+channelLabel ChColor = "color"+channelLabel ChFill = "fill"+channelLabel ChStroke = "stroke"+channelLabel ChStrokeWidth = "strokeWidth"+channelLabel ChShape = "shape"+channelLabel ChSize = "size"+channelLabel ChFillOpacity = "fillOpacity"+channelLabel ChStrokeOpacity = "strokeOpacity"+channelLabel ChOpacity = "opacity"+channelLabel ChText = "text"+channelLabel ChTooltip = "tooltip"+channelLabel ChHref = "href"+channelLabel ChKey = "key"+++{-|++Indicates whether or not a scale domain should be independent of others in a+composite visualization. See the+<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation> for+details.++For use with 'Resolve'.++-}+data Resolution+    = Shared+    | Independent+++resolutionLabel :: Resolution -> T.Text+resolutionLabel Shared = "shared"+resolutionLabel Independent = "independent"+++{-|++Used to determine how a channel's axis, scale or legend domains should be resolved+if defined in more than one view in a composite visualization. See the+<https://vega.github.io/vega-lite/docs/resolve.html Vega-Lite documentation>+for details.+-}+data Resolve+    = RAxis [(Channel, Resolution)]+    | RLegend [(Channel, Resolution)]+    | RScale [(Channel, Resolution)]+++resolveProperty :: Resolve -> ResolveSpec+resolveProperty res =+  let (nme, rls) = case res of+        RAxis chRules -> ("axis", chRules)+        RLegend chRules -> ("legend", chRules)+        RScale chRules -> ("scale", chRules)++      ans = map (\(ch, rule) -> channelLabel ch .= resolutionLabel rule) rls+  in RS (nme, object ans)+++-- | This is used with 'Graphics.Vega.VegaLite.bounds' to define the extent of a sub plot.+--+--   @since 0.4.0.0++data Bounds+  = Full+    -- ^ Bounds calculation should use the entire plot area (including axes, title,+    --   and legend).+  | Flush+    -- ^ Bounds calculation should take only the specified width and height values for+    --   a sub-view. Useful when attempting to place sub-plots without axes or legends into+    --   a uniform grid structure.+++boundsSpec :: Bounds -> VLSpec+boundsSpec Full = "full"+boundsSpec Flush = "flush"+++-- | Specifies the alignment of compositions. It is used with:+--   'Graphics.Vega.VegaLite.align', 'Graphics.Vega.VegaLite.alignRC', 'Graphics.Vega.VegaLite.LeGridAlign', and 'Graphics.Vega.VegaLite.LGridAlign'.+--+--   @since 0.4.0.0++data CompositionAlignment+    = CANone+    -- ^ Flow layout is used, where adjacent subviews are placed one after+    --   another.+    | CAEach+    -- ^ Each row and column may be of a variable size.+    | CAAll+    -- ^ All the rows and columns are of the same size (this is based on the+    --   maximum subview size).+++compositionAlignmentSpec :: CompositionAlignment -> VLSpec+compositionAlignmentSpec CANone = "none"+compositionAlignmentSpec CAEach = "each"+compositionAlignmentSpec CAAll = "all"+++-- | Specify the padding dimensions in pixel units.++data Padding+    = PSize Double+      -- ^ Use the same padding on all four edges of the container.+    | PEdges Double Double Double Double+      -- ^ Specify the padding for the left, top, right, and bottom edges.+++paddingSpec :: Padding -> VLSpec+paddingSpec (PSize p) = toJSON p+paddingSpec (PEdges l t r b) =+  object [ "left" .= l+         , "top" .= t+         , "right" .= r+         , "bottom" .= b+         ]+++{-|++Indicates the auto-sizing characteristics of the visualization such as amount+of padding, whether it should fill the parent container etc. For more details see the+<https://vega.github.io/vega-lite/docs/size.html#autosize Vega-Lite documentation>.++-}++data Autosize+    = AContent+      -- ^ Interpret visualization dimensions to be for the data rectangle (external+      --   padding added to this size).+    | AFit+      -- ^ Interpret visualization dimensions to be for the entire visualization (data+      --   rectangle is shrunk to accommodate external decorations padding).+    | AFitX+      -- ^ Interpret visualization width to be for the entire visualization width (data+      --   rectangle width is shrunk to accommodate external decorations padding).+      --+      --   @since 0.5.0.0+    | AFitY+      -- ^ Interpret visualization height to be for the entire visualization height (data+      --   rectangle height is shrunk to accommodate external decorations padding).+      --+      --   @since 0.5.0.0+    | ANone+      -- ^ No autosizing is applied.+    | APad+      -- ^ Automatically expand size of visualization from the given dimensions in order+      --   to fit in all supplementary decorations (legends etc.).+    | APadding+      -- ^ Interpret visualization width to be for the entire visualization (data+      -- rectangle is shrunk to accommodate external padding).+    | AResize+      -- ^ Recalculate autosizing on every view update.+++autosizeProperty :: Autosize -> LabelledSpec+autosizeProperty APad = "type" .= fromT "pad"+autosizeProperty AFit = "type" .= fromT "fit"+autosizeProperty AFitX = "type" .= fromT "fit-x"+autosizeProperty AFitY = "type" .= fromT "fit-y"+autosizeProperty ANone = "type" .= fromT "none"+autosizeProperty AResize = "resize" .= True+autosizeProperty AContent = "contains" .= fromT "content"+autosizeProperty APadding = "contains" .= fromT "padding"+++{-|++Create a list of fields to use in set of repeated small multiples. The list of+fields named here can be referenced in an encoding with @'Graphics.Vega.VegaLite.PRepeat' 'Graphics.Vega.VegaLite.Column'@+or @'Graphics.Vega.VegaLite.PRepeat' 'Graphics.Vega.VegaLite.Row'@.++-}+data RepeatFields+    = RowFields [FieldName]+    | ColumnFields [FieldName]+++repeatFieldsProperty :: RepeatFields -> LabelledSpec+repeatFieldsProperty (RowFields fs) = "row" .= fs+repeatFieldsProperty (ColumnFields fs) = "column" .= fs+++{-|++Indicates the type of color interpolation to apply, when mapping a data field+onto a color scale.++For details see the+<https://vega.github.io/vega-lite/docs/scale.html#continuous Vega-Lite documentation>.++-}+data CInterpolate+    = CubeHelix Double+      -- ^ Cube helix color interpolation for continuous color scales using the given+      --   gamma value (anchored at 1).+    | CubeHelixLong Double+      -- ^ Long-path cube helix color interpolation for continuous color scales using+      --   the given gamma value (anchored at 1).+    | Hcl+      -- ^ HCL color interpolation for continuous color scales.+    | HclLong+      -- ^ HCL color interpolation in polar coordinate space for continuous color scales.+    | Hsl+      -- ^ HSL color interpolation for continuous color scales.+    | HslLong+      -- ^ HSL color interpolation in polar coordinate space for continuous color scales.+    | Lab+      -- ^ Lab color interpolation for continuous color scales.+    | Rgb Double+      -- ^ RGB color interpolation for continuous color scales using the given gamma+      --   value (anchored at 1).+++-- Need to tie down some types as things are too polymorphic,+-- particularly in the presence of OverloadedStrings.+--+pairT :: T.Text -> T.Text -> (T.Text, A.Value)+pairT a b = a .= b+++cInterpolateSpec :: CInterpolate -> VLSpec+cInterpolateSpec (Rgb gamma) = object [pairT "type" "rgb", "gamma" .= gamma]+cInterpolateSpec Hsl = object [pairT "type" "hsl"]+cInterpolateSpec HslLong = object [pairT "type" "hsl-long"]+cInterpolateSpec Lab = object [pairT "type" "lab"]+cInterpolateSpec Hcl = object [pairT "type" "hcl"]+cInterpolateSpec HclLong = object [pairT "type" "hcl-long"]+cInterpolateSpec (CubeHelix gamma) = object [pairT "type" "cubehelix", "gamma" .= gamma]+cInterpolateSpec (CubeHelixLong gamma) = object [pairT "type" "cubehelix-long", "gamma" .= gamma]+++-- | The properties for a single view or layer background.+--+--   Used with 'Graphics.Vega.VegaLite.viewBackground' and+--   'Graphics.Vega.VegaLite.ViewBackgroundStyle'.+--+--   @since 0.4.0.0++data ViewBackground+    = VBStyle [T.Text]+    -- ^ A list of named styles to apply. A named style can be specified+    --   via 'Graphics.Vega.VegaLite.NamedStyle' or 'Graphics.Vega.VegaLite.NamedStyles'. Later styles in the list will+    --   override earlier ones if there is a conflict in any of the mark+    --   properties.+    | VBCornerRadius Double+    -- ^ The radius in pixels of rounded corners.+    | VBFill (Maybe Color)+    -- ^ Fill color.+    --+    --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    | VBFillOpacity Opacity+    -- ^ Fill opacity.+    | VBOpacity Opacity+    -- ^ Overall opacity.+    | VBStroke (Maybe Color)+    -- ^ The stroke color for a line around the background. If @Nothing@ then+    --   no line is drawn.+    --+    --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    | VBStrokeOpacity Opacity+    -- ^ The opacity of the line around the background, if drawn.+    | VBStrokeWidth Double+    -- ^ The width of the line around the background, if drawn.+    | VBStrokeCap StrokeCap+    -- ^ The cap line-ending for the line around the background, if drawn.+    | VBStrokeDash DashStyle+    -- ^ The dash pattern of the line around the background, if drawn.+    | VBStrokeDashOffset DashOffset+    -- ^ The offset of the dash pattern for the line around the background, if drawn.+    | VBStrokeJoin StrokeJoin+    -- ^ The line-joining style of the line around the background, if drawn.+    | VBStrokeMiterLimit Double+    -- ^ The mitre limit at which to bevel the line around the background, if drawn.+++viewBackgroundSpec :: ViewBackground -> LabelledSpec+viewBackgroundSpec (VBStyle [style]) = "style" .= style  -- special case singleton+viewBackgroundSpec (VBStyle styles) = "style" .= styles+viewBackgroundSpec (VBCornerRadius r) = "cornerRadius" .= r+viewBackgroundSpec (VBFill (Just s)) = "fill" .= s+viewBackgroundSpec (VBFill Nothing) = "fill" .= A.Null+viewBackgroundSpec (VBFillOpacity x) = "fillOpacity" .= x+viewBackgroundSpec (VBOpacity x) = "opacity" .= x+viewBackgroundSpec (VBStroke (Just s)) = "stroke" .= s+viewBackgroundSpec (VBStroke Nothing) = "stroke" .= A.Null+viewBackgroundSpec (VBStrokeOpacity x) = "strokeOpacity" .= x+viewBackgroundSpec (VBStrokeCap cap) = "strokeCap" .= strokeCapLabel cap+viewBackgroundSpec (VBStrokeJoin jn) = "strokeJoin" .= strokeJoinLabel jn+viewBackgroundSpec (VBStrokeWidth x) = "strokeWidth" .= x+viewBackgroundSpec (VBStrokeDash xs) = "strokeDash" .= fromDS xs+viewBackgroundSpec (VBStrokeDashOffset x) = "strokeDashOffset" .= x+viewBackgroundSpec (VBStrokeMiterLimit x) = "strokeMiterLimit" .= x+++{-|++Represents a facet header property. For details, see the+<https://vega.github.io/vega-lite/docs/facet.html#header Vega-Lite documentation>.++Labels refer to the title of each sub-plot in a faceted view and+title is the overall title of the collection.++-}++-- TODO: should there be a HLabelBaseline, HTitleFontStyle, ...?+--       However, the following covers the vega-lite 3.3.0 schema++data HeaderProperty+    = HFormat T.Text+      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html) for+      --   facet header (title) values. To distinguish between formatting as numeric values+      --   and data/time values, additionally use 'HFormatAsNum' or 'HFormatAsTemporal'.+    | HFormatAsNum+      -- ^ Facet headers should be formatted as numbers. Use a+      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)+      --   with 'HFormat'.+      --+      -- @since 0.4.0.0+    | HFormatAsTemporal+      -- ^ Facet headers should be formatted as dates or times. Use a+      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)+      --   with 'HFormat'.+      --+      -- @since 0.4.0.0+    | HTitle T.Text+      -- ^ The title for the facets.+    | HNoTitle+      -- ^ Draw no title for the facets.+      --+      -- @since 0.4.0.0+    | HLabelAlign HAlign+      -- ^ The horizontal alignment of the labels.+      --+      -- @since 0.4.0.0+    | HLabelAnchor APosition+      -- ^ The anchor position for the labels.+      --+      -- @since 0.4.0.0+    | HLabelAngle Angle+      -- ^ The angle to draw the labels.+      --+      -- @since 0.4.0.0+    | HLabelColor Color+      -- ^ The color of the labels.+      --+      -- @since 0.4.0.0+    | HLabelFont T.Text+      -- ^ The font for the labels.+      --+      -- @since 0.4.0.0+    | HLabelFontSize Double+      -- ^ The font size for the labels.+      --+      -- @since 0.4.0.0+    | HLabelLimit Double+      -- ^ The maximum length of each label.+      --+      -- @since 0.4.0.0+    | HLabelOrient Side+      -- ^ The position of the label relative to its sub-plot.+      --+      -- @since 0.4.0.0+    | HLabelPadding Double+      -- ^ The spacing in pixels between the label and its sub-plot.+      --+      -- @since 0.4.0.0+    | HTitleAlign HAlign+      -- ^ The horizontal alignment of the title.+      --+      -- @since 0.4.0.0+    | HTitleAnchor APosition+      -- ^ The anchor position for the title.+      --+      -- @since 0.4.0.0+    | HTitleAngle Angle+      -- ^ The angle to draw the title.+      --+      -- @since 0.4.0.0+    | HTitleBaseline VAlign+      -- ^ The vertical alignment of the title.+      --+      -- @since 0.4.0.0+    | HTitleColor Color+      -- ^ The color of the title.+      --+      -- @since 0.4.0.0+    | HTitleFont T.Text+      -- ^ The font for the title.+      --+      -- @since 0.4.0.0+    | HTitleFontSize Double+      -- ^ The font size for the title.+      --+      -- @since 0.4.0.0+    | HTitleFontWeight T.Text+      -- ^ The font weight for the title.+      --+      -- @since 0.4.0.0+    | HTitleLimit Double+      -- ^ The maximum length of the title.+      --+      -- @since 0.4.0.0+    | HTitleOrient Side+      -- ^ The position of the title relative to the sub-plots.+      --+      -- @since 0.4.0.0+    | HTitlePadding Double+      -- ^ The spacing in pixels between the title and the labels.+      --+      -- @since 0.4.0.0+++headerProperty :: HeaderProperty -> LabelledSpec+headerProperty (HFormat fmt) = "format" .= fmt+headerProperty HFormatAsNum = "formatType" .= fromT "number"+headerProperty HFormatAsTemporal = "formatType" .= fromT "time"+headerProperty (HTitle ttl) = "title" .= splitOnNewline ttl+headerProperty HNoTitle = "title" .= A.Null+headerProperty (HLabelAlign ha) = "labelAlign" .= hAlignLabel ha+headerProperty (HLabelAnchor a) = "labelAnchor" .= anchorLabel a+headerProperty (HLabelAngle x) = "labelAngle" .= x+headerProperty (HLabelColor s) = "labelColor" .= fromColor s+headerProperty (HLabelFont s) = "labelFont" .= s+headerProperty (HLabelFontSize x) = "labelFontSize" .= x+headerProperty (HLabelLimit x) = "labelLimit" .= x+headerProperty (HLabelOrient orient) = "labelOrient" .= sideLabel orient+headerProperty (HLabelPadding x) = "labelPadding" .= x+headerProperty (HTitleAlign ha) = "titleAlign" .= hAlignLabel ha+headerProperty (HTitleAnchor a) = "titleAnchor" .= anchorLabel a+headerProperty (HTitleAngle x) = "titleAngle" .= x+headerProperty (HTitleBaseline va) = "titleBaseline" .= vAlignLabel va+headerProperty (HTitleColor s) = "titleColor" .= fromColor s+headerProperty (HTitleFont s) = "titleFont" .= s+headerProperty (HTitleFontWeight s) = "titleFontWeight" .= s+headerProperty (HTitleFontSize x) = "titleFontSize" .= x+headerProperty (HTitleLimit x) = "titleLimit" .= x+headerProperty (HTitleOrient orient) = "titleOrient" .= sideLabel orient+headerProperty (HTitlePadding x) = "titlePadding" .= x
+ src/Graphics/Vega/VegaLite/Geometry.hs view
@@ -0,0 +1,490 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Geometry+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings++Geometric shapes and projections.++-}++module Graphics.Vega.VegaLite.Geometry+       ( geometry+       , geoFeatureCollection+       , geometryCollection+       , Geometry(..)++       , sphere+       , graticule+       , GraticuleProperty(..)++       , projection+       , ProjectionProperty(..)+       , Projection(..)+       , ClipRect(..)++       -- not for external export+       , projectionProperty++       ) where++import qualified Data.Aeson as A+import qualified Data.Text as T++import Control.Arrow (second)+import Data.Aeson ((.=), object, toJSON)++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif+++import Graphics.Vega.VegaLite.Data+  ( DataValue+  , dataValueSpec+  )+import Graphics.Vega.VegaLite.Foundation (fromT)+import Graphics.Vega.VegaLite.Specification+  ( VLProperty(VLData, VLProjection)+  , VLSpec+  , LabelledSpec+  , PropertySpec+  )+import Graphics.Vega.VegaLite.Input+  ( Data+  )+++type_ :: T.Text -> LabelledSpec+type_ t = "type" .= t+++{-|++Specifies a list of geo features to be used in a geoShape specification.+Each feature object in this collection can be created with the 'geometry'+function.++@+'geoFeatureCollection'+    [ 'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( -3, 52 ), ( 4, 52 ), ( -3, 59 ) ] ])+        [ ( "myRegionName", 'Graphics.Vega.VegaLite.Str' "Northern region" ) ]+    , 'geometry' ('GeoPolygon' [ [ ( -3, 52 ), ( 4, 52 ), ( 4, 45 ), ( -3, 52 ) ] ])+        [ ( "myRegionName", 'Graphics.Vega.VegaLite.Str' "Southern region" ) ]+    ]+@+-}+geoFeatureCollection :: [VLSpec] -> VLSpec+geoFeatureCollection geoms =+  object [ type_ "FeatureCollection"+         , "features" .=  geoms+         ]+++{-|++Specifies a list of geometry objects to be used in a geoShape specification.+Each geometry object in this collection can be created with the 'geometry'+function.++@+'geometryCollection'+    [ 'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []+    , 'geometry' ('GeoPoint' -3.5 55.5) []+    ]+@+-}+geometryCollection :: [VLSpec] -> VLSpec+geometryCollection geoms =+  object [ type_ "GeometryCollection"+         , "geometries" .= geoms+         ]+++{-|++Types of geographic map projection. These are based on a subset of those provided+by the <https://github.com/d3/d3-geo d3-geo library>. For details of available+projections see the+<https://vega.github.io/vega-lite/docs/projection.html#projection-types Vega-Lite documentation>.+-}++-- based on schema 3.3.0 #/definitions/ProjectionType++data Projection+    = Albers+      -- ^ An Albers equal-area conic map projection.+    | AlbersUsa+      -- ^ An Albers USA map projection that combines continental USA with+      --   Alaska and Hawaii. Unlike other projection types, this remains+      --   unaffected by 'PrRotate'.+    | AzimuthalEqualArea+      -- ^ An azimuthal equal area map projection.+    | AzimuthalEquidistant+      -- ^ An azimuthal equidistant map projection.+    | ConicConformal+      -- ^ A conformal conic map projection.+    | ConicEqualArea+      -- ^ An equal area conic map projection.+    | ConicEquidistant+      -- ^ An equidistant conic map projection.+    | Custom T.Text+      -- ^ Specify the name of the custom D3 prohection to use. See the+      --   <https://vega.github.io/vega/docs/projections/#register Vega API>+      --   for more information.+      --+      --   An example: @Custom "winkle3"@+    | EqualEarth+      -- ^ An <https://github.com/d3/d3-geo#equal-earth Equal Earth map projection>+      --   that provides a reasonable shape approximation while retaining relative areas.+      --+      --   @since 0.5.0.0+    | Equirectangular+      -- ^ An equirectangular map projection that maps longitude to x and latitude to y.+      --   While showing less area distortion towards the poles than the default 'Mercator'+      --   projection, it is neither equal-area nor conformal.+    | Gnomonic+      -- ^ A gnomonic map projection.+    | Identity+      -- ^ The identiy projection. This can be combined with 'PrReflectX' and+      --   'PrReflectY' in the list of projection properties.+      --+      --   @since 0.4.0.0+    | Mercator+      -- ^ A Mercator map projection. This is the default projection of longitude, latitude+      --   values if no projection is set explicitly. It preserves shape (local angle) and+      --   lines of equal angular bearing remain parallel straight lines. The area is+      --   /significantly/ enlarged towards the poles.+    | NaturalEarth1+      -- ^ The <https://github.com/d3/d3-geo#geoNaturalEarth1 Natural Earth projection>+      --   is neither conformal nor equal-area, but is designed to be \"appealing to the+      --   eye\" for small-scale maps of the whole world.+      --+      --   @since 0.5.0.0+    | Orthographic+      -- ^ An orthographic map projection.+    | Stereographic+      -- ^ A stereographic map projection.+    | TransverseMercator+      -- ^ A transverse Mercator map projection.+++projectionLabel :: Projection -> T.Text+projectionLabel Albers = "albers"+projectionLabel AlbersUsa = "albersUsa"+projectionLabel AzimuthalEqualArea = "azimuthalEqualArea"+projectionLabel AzimuthalEquidistant = "azimuthalEquidistant"+projectionLabel ConicConformal = "conicConformal"+projectionLabel ConicEqualArea = "conicEqualarea"+projectionLabel ConicEquidistant = "conicEquidistant"+projectionLabel (Custom pName) = pName+projectionLabel EqualEarth = "equalEarth"+projectionLabel Equirectangular = "equirectangular"+projectionLabel Gnomonic = "gnomonic"+projectionLabel Identity = "identity"+projectionLabel Mercator = "mercator"+projectionLabel NaturalEarth1 = "naturalEarth1"+projectionLabel Orthographic = "orthographic"+projectionLabel Stereographic = "stereographic"+projectionLabel TransverseMercator = "transverseMercator"+++-- | Specifies a clipping rectangle for defining+--   the clip extent of a map projection.++data ClipRect+    = NoClip+      -- ^ No clipping it to be applied.+    | LTRB Double Double Double Double+      -- ^ The left, top, right, and bottom extents, in pixels,+      --   of a rectangular clip.+++{-|++Properties for customising a geospatial projection that converts longitude,latitude+pairs into planar @(x,y)@ coordinate pairs for rendering and query. For details see the+<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.++This type has been changed in the @0.4.0.0@ release so that all constructors+start with @Pr@ rather than @P@ (and so provide some differentiation to the+'Graphics.Vega.VegaLite.PositionChannel' constructors).++-}++-- based on schema 3.3.0 #/definitions/Projection++data ProjectionProperty+    = PrType Projection+      -- ^ The type of the map projection.+    | PrClipAngle (Maybe Double)+      -- ^ The clipping circle angle in degrees. A value of @Nothing@ will switch to+      --   antimeridian cutting rather than small-circle clipping.+    | PrClipExtent ClipRect+      -- ^ Projection’s viewport clip extent to the specified bounds in pixels.+    | PrCenter Double Double+      -- ^ Projection’s center as longitude and latitude in degrees.+    | PrScale Double+      -- ^ The projection's zoom scale, which if set, overrides automatic scaling of a+      --   geo feature to fit within the viewing area.+      --+      --   @since 0.4.0.0+    | PrTranslate Double Double+      -- ^ A projection’s panning translation, which if set, overrides automatic positioning+      --   of a geo feature to fit within the viewing area+      --+      --   Note that the prefix is @Pr@ and not @P@, to match the Elm API.+      --+      --   @since 0.4.0.0+    | PrRotate Double Double Double+      -- ^ A projection’s three-axis rotation angle. The order is @lambda@ @phi@ @gamma@,+      --   and specifies the rotation angles in degrees about each spherical axis.+    | PrPrecision Double+      -- ^ Threshold for the projection’s adaptive resampling in pixels, and corresponds to the+      --   Douglas–Peucker distance. If precision is not specified, the projection’s current+      --   resampling precision of 0.707 is used.+      --+      --   Version 3.3.0 of the Vega-Lite spec claims this should be output as a string,+      --   but it is written out as a number since the+      --   [spec is in error](https://github.com/vega/vega-lite/issues/5190).+    | PrReflectX Bool+      -- ^ Reflect the x-coordinates after performing an identity projection. This+      --   creates a left-right mirror image of the geoshape marks when subject to an+      --   identity projection with 'Identity'.+      --+      -- @since 0.4.0.0+    | PrReflectY Bool+      -- ^ Reflect the y-coordinates after performing an identity projection. This+      --   creates a left-right mirror image of the geoshape marks when subject to an+      --   identity projection with 'Identity'.+      --+      -- @since 0.4.0.0+    | PrCoefficient Double+      -- ^ The @Hammer@ map projection coefficient.+    | PrDistance Double+      -- ^ The @Satellite@ map projection distance.+    | PrFraction Double+      -- ^ The @Bottomley@ map projection fraction.+    | PrLobes Int+      -- ^ Number of lobes in lobed map projections such as the @Berghaus star@.+    | PrParallel Double+      -- ^ Parallel for map projections such as the @Armadillo@.+    | PrRadius Double+      -- ^ Radius value for map projections such as the @Gingery@.+    | PrRatio Double+      -- ^ Ratio value for map projections such as the @Hill@.+    | PrSpacing Double+      -- ^ Spacing value for map projections such as the @Lagrange@.+    | PrTilt Double+      -- ^ @Satellite@ map projection tilt.+++projectionProperty :: ProjectionProperty -> LabelledSpec+projectionProperty (PrType proj) = "type" .= projectionLabel proj+projectionProperty (PrClipAngle numOrNull) = "clipAngle" .= maybe A.Null toJSON numOrNull+projectionProperty (PrClipExtent rClip) =+  ("clipExtent", case rClip of+    NoClip -> A.Null+    LTRB l t r b -> toJSON (map toJSON [l, t, r, b])+  )+projectionProperty (PrCenter lon lat) = "center" .= [lon, lat]+projectionProperty (PrScale sc) = "scale" .= sc+projectionProperty (PrTranslate tx ty) = "translate" .= [tx, ty]+projectionProperty (PrRotate lambda phi gamma) = "rotate" .= [lambda, phi, gamma]+projectionProperty (PrPrecision pr) = "precision" .= pr  -- the 3.3.0 spec says this is a string, but that's wrong,  See https://github.com/vega/vega-lite/issues/5190+projectionProperty (PrReflectX b) = "reflectX" .= b+projectionProperty (PrReflectY b) = "reflectY" .= b+projectionProperty (PrCoefficient x) = "coefficient" .= x+projectionProperty (PrDistance x) = "distance" .= x+projectionProperty (PrFraction x) = "fraction" .= x+projectionProperty (PrLobes n) = "lobes" .= n+projectionProperty (PrParallel x) = "parallel" .= x+projectionProperty (PrRadius x) = "radius" .= x+projectionProperty (PrRatio x) = "ratio" .= x+projectionProperty (PrSpacing x) = "spacing" .= x+projectionProperty (PrTilt x) = "tilt" .= x+++{-|++Sets the cartographic projection used for geospatial coordinates. A projection+defines the mapping from @(longitude,latitude)@ to an @(x,y)@ plane used for rendering.+This is useful when using the 'Graphics.Vega.VegaLite.Geoshape' mark. For further details see the+<https://vega.github.io/vega-lite/docs/projection.html Vega-Lite documentation>.++@+'projection' [ 'PrType' 'Orthographic', 'PrRotate' (-40) 0 0 ]+@+-}+projection :: [ProjectionProperty] -> PropertySpec+projection pProps = (VLProjection, object (map projectionProperty pProps))+++{-|++Specifies the type and content of geometry specifications for programatically+creating GeoShapes. These can be mapped to the+<https://tools.ietf.org/html/rfc7946#section-3.1 GeoJson geometry object types>+where the pluralised type names refer to their @Multi@ prefixed equivalent in the+GeoJSON specification.+-}+data Geometry+    = GeoPoint Double Double+    -- ^ The GeoJson geometry @point@ type.+    | GeoPoints [(Double, Double)]+    -- ^ The GeoJson geometry @multi-point@ type.+    | GeoLine [(Double, Double)]+    -- ^ The GeoJson geometry @line@ type.+    | GeoLines [[(Double, Double)]]+    -- ^ The GeoJson geometry @multi-line@ type.+    | GeoPolygon [[(Double, Double)]]+    -- ^ The GeoJson geometry @polygon@ type.+    | GeoPolygons [[[(Double, Double)]]]+    -- ^ The GeoJson geometry @multi-polygon@ type.+++{-|++Specifies a geometric object to be used in a geoShape specification. The first+parameter is the geometric type, the second an optional list of properties to be+associated with the object.++@+'geometry' ('GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []+@+-}+geometry :: Geometry -> [(T.Text, DataValue)] -> VLSpec+geometry gType properties =+  object ([ ("type", fromT "Feature")+          , ("geometry", geometryTypeSpec gType) ]+          <> if null properties+             then []+             else [("properties",+                    object (map (second dataValueSpec) properties))]+         )+++geometryTypeSpec :: Geometry -> VLSpec+geometryTypeSpec gType =+  let toCoords :: [(Double, Double)] -> VLSpec+      toCoords = toJSON -- rely on Aeson converting a pair to a 2-element list++      toCoordList :: [[(Double, Double)]] -> VLSpec+      toCoordList = toJSON . map toCoords  -- this is just toJSON isn't it?++      -- can we replace this infinite tower of toJSON calls with one toJSON call?+      (ptype, cs) = case gType of+        GeoPoint x y -> ("Point", toJSON [x, y])+        GeoPoints coords -> ("MultiPoint", toCoords coords)+        GeoLine coords -> ("LineString", toCoords coords)+        GeoLines coords -> ("MultiLineString", toCoordList coords)+        GeoPolygon coords -> ("Polygon", toCoordList coords)+        GeoPolygons ccoords -> ("MultiPolygon", toJSON (map toCoordList ccoords))++  in object [("type", ptype), ("coordinates", cs)]+++{-|++Generate a data source that is a sphere for bounding global geographic data.+The sphere will be subject to whatever projection is specified for the view.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'sphere'+    , 'projection' [ 'PrType' 'Orthographic' ]+    , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Geoshape' [ 'Graphics.Vega.VegaLite.MFill' "aliceblue" ]+    ]+@++@since 0.4.0.0+-}+sphere :: Data+sphere = (VLData, object ["sphere" .= True])+++{-|++Generate a grid of lines of longitude (meridians) and latitude+(parallels).++@+let proj = 'projection' [ 'PrType' 'Orthographic' ]+    sphereSpec = 'Graphics.Vega.VegaLite.asSpec' [ 'sphere'+                        , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Geoshape' [ 'Graphics.Vega.VegaLite.MFill' "aliceblue" ] ]+    gratSpec =+        'Graphics.Vega.VegaLite.asSpec'+            [ 'graticule' [ 'GrStep' (5, 5) ]+            , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Geoshape' [ 'Graphics.Vega.VegaLite.MFilled' False, 'Graphics.Vega.VegaLite.MStrokeWidth' 0.3 ]+            ]+in 'Graphics.Vega.VegaLite.toVegaLite' [ proj, 'Graphics.Vega.VegaLite.layer' [ sphereSpec, gratSpec ] ]+@++@since 0.4.0.0++-}+graticule ::+  [GraticuleProperty] -- ^ An empty list uses the default parameters+  -> Data+graticule [] = (VLData, object ["graticule" .= True])+graticule grProps =+  (VLData, object ["graticule" .= object (map graticuleProperty grProps)])+++{-|++Determine the properties of graticules. See the+<https://vega.github.io/vega-lite/docs/data.html#graticule Vega-Lite documentation> for details.++@since 0.4.0.0++-}+data GraticuleProperty+    = GrExtent (Double, Double) (Double, Double)+    -- ^ Define the extent of both the major and minor graticules.+    --   The range is given as longitude, latitude pairs of the+    --   minimum and then maximum extent. The units are degrees.+    | GrExtentMajor (Double, Double) (Double, Double)+    -- ^ As @GrExtent@ but for the major graticule lines only.+    | GrExtentMinor (Double, Double) (Double, Double)+    -- ^ As @GrExtent@ but for the minor graticule lines only.+    | GrStep (Double, Double)+    -- ^ The step angles for the graticule lines, given as a longitude,+    --   latitude pair defining the EW and NS intervals respectively.+    --   The units are degrees.+    --+    --   By default major graticule lines extend to both poles but the+    --   minor lines stop at ±80 degrees latitude.+    | GrStepMajor (Double, Double)+    -- ^ As @GrStep@ but for the major graticule lines only.+    --+    --   The default is @(90, 360)@.+    | GrStepMinor (Double, Double)+    -- ^ As @GrStep@ but for the minor graticule lines only.+    --+    --   The default is @(10, 10)@.+    | GrPrecision Double+    -- ^ The precision of the graticule. The units are degrees.+    --   A smaller value reduces visual artifacts (steps) but takes longer+    --   to render.+    --+    --   The default is @2.5@.+++graticuleProperty :: GraticuleProperty -> LabelledSpec+graticuleProperty (GrExtent (lng1, lat1) (lng2, lat2)) =+  "extent" .= [[lng1, lat1], [lng2, lat2]]+graticuleProperty (GrExtentMajor (lng1, lat1) (lng2, lat2)) =+  "extentMajor" .= [[lng1, lat1], [lng2, lat2]]+graticuleProperty (GrExtentMinor (lng1, lat1) (lng2, lat2)) =+  "extentMinor" .= [[lng1, lat1], [lng2, lat2]]+graticuleProperty (GrStep (lng, lat)) = "step" .= [lng, lat]+graticuleProperty (GrStepMajor (lng, lat)) = "stepMajor" .= [lng, lat]+graticuleProperty (GrStepMinor (lng, lat)) = "stepMinor" .= [lng, lat]+graticuleProperty (GrPrecision x) = "precision" .= x
+ src/Graphics/Vega/VegaLite/Input.hs view
@@ -0,0 +1,595 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}++{-|+Module      : Graphics.Vega.VegaLite.Input+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings, TupleSections++Data input (from file or created inline).++-}++module Graphics.Vega.VegaLite.Input+       ( Data+       , DataColumn+       , DataRow++       , Format(..)+       , DataType(..)++       , dataFromUrl+       , dataFromColumns+       , dataFromRows+       , dataFromJson+       , dataFromSource+       , dataName+       , datasets+       , dataColumn+       , dataRow+       , noData++       , dataSequence+       , dataSequenceAs++       ) where++import qualified Data.Aeson as A+import qualified Data.HashMap.Strict as HM+import qualified Data.Text as T++import Control.Arrow (second)++import Data.Aeson ((.=), Value, decode, encode, object, toJSON)+import Data.Maybe (fromMaybe, mapMaybe)++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif++import Graphics.Vega.VegaLite.Data+  ( DataValue(..)+  , DataValues(..)+  , dataValueSpec+  )+import Graphics.Vega.VegaLite.Foundation+  ( FieldName+  )+import Graphics.Vega.VegaLite.Specification+  ( VLProperty(VLData, VLDatasets)+  , VLSpec+  , LabelledSpec+  )+import Graphics.Vega.VegaLite.Time (dateTimeProperty)+++{-|++Indicates the type of data to be parsed when reading input data. For @FoDate@+and @FoUtc@, the formatting specification can be specified using+<https://vega.github.io/vega-lite/docs/data.html#format D3's formatting specifiers>+or left as an empty string if default date formatting is to be applied. Care should+be taken when assuming default parsing of dates because different browsers can+parse dates differently. Being explicit about the date format is usually safer.++-}+data DataType+    = FoNumber+      -- ^ Indicate numeric data type to be parsed when reading input data.+    | FoBoolean+      -- ^ Indicate Boolean data type to be parsed when reading input data.+    | FoDate T.Text+      -- ^ Date format for parsing input data using+      --   [D3's formatting specifiers](https://vega.github.io/vega-lite/docs/data.html#format)+      --   or left as an empty string for default formatting.+    | FoUtc T.Text+      -- ^ Similar to 'FoDate' but for UTC format dates.+++{-|++Specifies the type of format a data source uses. If the format is indicated by+the file name extension (@".tsv"@, @".csv"@, @".json"@) there is no need to indicate the+format explicitly. However this can be useful if the filename extension does not+indicate type (e.g. @".txt"@) or you wish to customise the parsing of a file. For+example, when specifying the @JSON@ format, its parameter indicates the name of+property field containing the attribute data to extract. For details see the+<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>.+-}+data Format+    = JSON T.Text+      -- ^ Property to be extracted from some JSON when it has some surrounding structure.+      --   e.g., specifying the property @values.features@ is equivalent to retrieving+      --   @json.values.features@ from a JSON object with a custom delimiter.+    | CSV+      -- ^ Comma-separated (CSV) data file format.+    | TSV+      -- ^ Tab-separated (TSV) data file format+    | DSV Char+      -- ^ The fields are separated by the given character (which must be a+      --   single 16-bit code unit).+      --+      --   @since 0.4.0.0+      {- This isn't in the current vega-lite v3 schema as far as I can see+    | Arrow+      -- ^ <https://observablehq.com/@theneuralbit/introduction-to-apache-arrow Apache Arrow> format.+      --+      -- @since 0.4.0.0+      -}+    | TopojsonFeature T.Text+      -- ^ A topoJSON feature format containing an object with the given name. For example:+      --+      -- @+      -- 'dataFromUrl' \"londonBoroughs.json\" ['TopojsonFeature' \"boroughs\"]+      -- @+    | TopojsonMesh T.Text+      -- ^ A topoJSON mesh format containing an object with the given name. Unlike+      --   'TopojsonFeature', the corresponding geo data are returned as a single unified mesh,+      --   not as individual GeoJSON features.+    | Parse [(FieldName, DataType)]+      -- ^ Parsing rules when processing some data text, specified as+      --   a list of tuples in the form @(fieldname,+      --   datatype)@. Useful when automatic type inference needs to+      --   be overridden, for example when converting integers representing+      --   years into dates and strings into numbers:+      --+      -- @+      -- 'dataFromUrl' \"myDataFile.csv\"+      --    [ 'Parse' [ ( \"year\", 'FoDate' \"%Y\" ), ( "\y\", 'FoNumber' ) ] ]+      -- @+++{-|++Represents a single column of data. Used when generating inline data with+'dataColumn' and 'dataFromColumns'.+-}+type DataColumn = [LabelledSpec]++{-|++Represents a single row of data. Used when generating inline data with+'dataRow' and 'dataFromRows'.+-}+type DataRow = VLSpec++{-|++Convenience type-annotation label for use with data generation functions.++@+myRegion : ['DataColumn'] -> 'Data'+myRegion =+    'dataFromColumns' []+        . 'dataColumn' "easting" ('Graphics.Vega.VegaLite.Numbers' [ -3, 4, 4, -3, -3 ])+        . 'dataColumn' "northing" ('Graphics.Vega.VegaLite.Numbers' [ 52, 52, 45, 45, 52 ])+@++It is the same as 'Graphics.Vega.VegaLite.PropertySpec' (which was added in @0.4.0.0@),+but kept separate to help better-document code.++-}+type Data = (VLProperty, VLSpec)+++formatProperty :: Format -> [LabelledSpec]+formatProperty (JSON js) =+  let ps = [("type", "json")]+           <> if T.null (T.strip js) then [] else [("property", js)]+  in map (second toJSON) ps++formatProperty CSV = [("type", "csv")]+formatProperty TSV = [("type", "tsv")]+formatProperty (DSV delim) = [("type", "dsv"), "delimiter" .= delim]+-- formatProperty Arrow = [("type", "arrow")]+formatProperty (TopojsonFeature os) = [("type", "topojson")+                                      , "feature" .= os+                                      ]+formatProperty (TopojsonMesh os) = [("type", "topojson")+                                   , "mesh" .= os+                                   ]+formatProperty (Parse fmts) =+  let pObj = object (map (second dataTypeSpec) fmts)+  in [("parse", pObj)]+++dataTypeSpec :: DataType -> VLSpec+dataTypeSpec dType =+  let s = case dType of+        FoNumber -> "number"+        FoBoolean -> "boolean"+        FoDate fmt | T.null fmt -> "date"+                   | otherwise -> "date:'" <> fmt <> "'"+        FoUtc fmt | T.null fmt -> "utc"+                  | otherwise -> "utc:'" <> fmt <> "'"+  in toJSON s+++{-|++Create a row of data. A row comprises a list of (columnName, value) pairs.+The final parameter is the list of any other rows to which this is added.++This is expected to be used with 'dataFromRows'.++@+'dataRow' [(\"Animal\", 'Graphics.Vega.VegaLite.Str' \"Fish\"), (\"Age\", 'Graphics.Vega.VegaLite.Number' 28), (\"Year\", 'Graphics.Vega.VegaLite.Str' "2010")] []+@+-}+dataRow :: [(FieldName, DataValue)] -> [DataRow] -> [DataRow]+dataRow rw = (object (map (second dataValueSpec) rw) :)+++{-|++Create a dataset comprising a collection of named 'Data' items. Each data item+can be created with normal data generating functions such as 'dataFromRows' or+'dataFromJson'. These can be later referred to using 'dataFromSource'.++@+let toJS = Data.Aeson.toJSON+    obj = Data.Aeson.object++    dvals = 'dataFromRows' []+            . 'dataRow' [ ( "cat", 'Graphics.Vega.VegaLite.Str' "a" ), ( "val", 'Graphics.Vega.VegaLite.Number' 10 ) ]+            . 'dataRow' [ ( "cat", 'Graphics.Vega.VegaLite.Str' "b" ), ( "val", 'Graphics.Vega.VegaLite.Number' 18 ) ]+    json = toJS+            [ obj [ ( "cat", toJS "a" ), ( "val", toJS 120 ) ]+            , obj [ ( "cat", toJS "b" ), ( "val", toJS 180 ) ]+            ]++    enc = ...++in 'Graphics.Vega.VegaLite.toVegaLite'+    [ 'datasets' [ ( \"myData\", dvals [] ),  ( \"myJson\", 'dataFromJson' json [] ) ]+    , 'dataFromSource' \"myData\" []+    , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Bar' []+    , enc []+    ]+@+-}+datasets :: [(T.Text, Data)] -> Data+datasets namedData =+  -- Follow Elm in parsing the structure to get what we want, but the code is+  -- written rather differently.+  --+  -- The input is expected to be a singleton list containing a pair.+  let converted = extract . snd+      specs = map (second converted) namedData++      convert :: Value -> Maybe [(T.Text, Value)]+      convert v = HM.toList <$> decode (encode v)++      extract din =+        let extract' [(_, v)] = Just v+            extract' _ = Nothing++        in fromMaybe din (convert din >>= extract')++  in (VLDatasets, object specs)+++-- | This is for composed specifications, and it tells the visualization to+--   ignore the data from the parent.+--+--   @since 0.4.0.0+noData :: Data+noData = (VLData, A.Null)+++{-|++Name to give a data source. Useful when a specification needs to reference a+data source, such as one generated via an API call.++@+dvals = 'dataName' \"myName\" ('dataFromUrl' \"myData.json\" [])+@++@since 0.4.0.0++-}++-- TODO: can we restrict this to only those with a VLProperty of VLData?++dataName ::+  T.Text+  -- ^ The name to give the data source+  -> Data+  -- ^ The data source to be named.+  -> Data+  -- ^ If the input @Data@ argument is not a data source then+  --   this is just the input value.+dataName s odata@(_, dataSpec) =+  -- follow Elm in parsing the structure to get what we want, but the code is+  -- written rather differently. This is based on the code used in datasets.+  --+  -- The input is expected to be a singleton list containing a pair.+  --+  let converted = convert >>= extract++      -- Aeson's objects are wrappers around a hash map, so this should be+      -- a relatively easy conversion. The type annotation isn't needed+      -- but left in for reference.+      --+      convert :: Maybe [(T.Text, Value)]+      convert = HM.toList <$> decode (encode dataSpec)++      extract [v] = Just v+      extract _ = Nothing++  in case converted of+       Just v -> (VLData, object [ "name" .= s, v ])+       _ -> odata+++{-|++Declare a data source from a list of column values. Each column has a+specific type (e.g. 'Number' or 'String'), but different columns can have+different types.++Note that the columns are truncated to match the length of the shortest column.++@+'dataFromColumns' [ 'Parse' [ ( \"Year\", 'FoDate' "%Y" ) ] ]+  . 'dataColumn' \"Animal\" ('Strings' [ \"Fish\", \"Dog\", \"Cat\" ])+  . 'dataColumn' \"Age\" ('Numbers' [ 28, 12, 6 ])+  . 'dataColumn' \"Year\" ('Strings' [ "2010", "2014", "2015" ])+@+-}+dataFromColumns ::+  [Format]+  -- ^ An optional list of formatting instructions for the columns.+  --+  --   Simple numbers and strings do not normally need formatting, but it is+  --   good practice to explicitly declare date-time formats as handling of+  --   these values can vary between different viewers (e.g. browsers).+  --+  --   See the+  --   <https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>+  --   for more details.+  -> [DataColumn]+  -- ^ The columns to add. This is expected to be created with one or more+  --   calls to 'dataColumn'.+  -> Data+dataFromColumns fmts cols =+  let dataArray = map object (transpose cols)++      vals = [("values", toJSON dataArray)]+             <> if null fmts+                then []+                else [("format", toJSON fmtObject)]++      fmtObject = object (concatMap formatProperty fmts)++  in (VLData, object vals)+++transpose :: [[a]] -> [[a]]+transpose [] = []+transpose ([]:xss) = transpose xss+transpose ((x:xs) : xss) =+  let heads = filterMap elmHead xss --+      tails = filterMap elmTail xss++      elmHead (h:_) = Just h+      elmHead [] = Nothing++      elmTail [] = Nothing+      elmTail (_:ts) = Just ts++      filterMap = mapMaybe++  in (x : heads) : transpose (xs : tails)+++{-|++Declare a data source from a provided json specification. The most likely use-case+for specifying json inline is when creating <http://geojson.org geojson> objects,+when 'Graphics.Vega.VegaLite.geometry', 'Graphics.Vega.VegaLite.geometryCollection', and 'Graphics.Vega.VegaLite.geoFeatureCollection' functions+may be used. For more general cases of json creation, consider 'Data.Aeson.encode'.++@+let geojson =+        'Graphics.Vega.VegaLite.geometry' ('Graphics.Vega.VegaLite.GeoPolygon' [ [ ( -3, 59 ), ( 4, 59 ), ( 4, 52 ), ( -3, 59 ) ] ]) []+in 'Graphics.Vega.VegaLite.toVegaLite'+    [ 'Graphics.Vega.VegaLite.width' 200+    , 'Graphics.Vega.VegaLite.height' 200+    , 'dataFromJson' geojson []+    , 'Graphics.Vega.VegaLite.projection' [ 'Graphics.Vega.VegaLite.PrType' 'Graphics.Vega.VegaLite.Orthographic' ]+    , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Geoshape' []+    ]+@+-}+dataFromJson :: VLSpec -> [Format] -> Data+dataFromJson vlspec fmts =+  let js = if null fmts+           then object [("values", vlspec)]+           else object [ ("values", vlspec)+                       , ("format",+                          object (concatMap formatProperty fmts)) ]+  in (VLData, js)+++{-|++Create a column of data. A column has a name and a list of values. The final+parameter is the list of any other columns to which this is added.++This is expected to be used with 'dataFromColumns'.++@+'dataColumn' \"Animal\" ('Strings' [ \"Cat\", \"Dog\", \"Mouse\"]) []+@+-}+dataColumn :: FieldName -> DataValues -> [DataColumn] -> [DataColumn]+dataColumn colName dVals xs =+  let col = case dVals of+        Booleans cs -> map toJSON cs+        DateTimes cs -> map dtToJSON cs+        Numbers cs -> map toJSON cs+        Strings cs -> map toJSON cs++      dtToJSON = object . map dateTimeProperty+      x = map (colName,) col++  in x : xs+++{-|++Declare a data source from a provided list of row values. Each row+contains a list of tuples where the first value is a string+representing the column name, and the second the column value for that+row. Each column can have a value of a different type but+__you must ensure__+that when subsequent rows are added, they match the types of+previous values with shared column names.++Note though that generally if you are creating data inline (as opposed+to reading from a file), adding data by column is more efficient and+less error-prone.++@+dataFromRows [ 'Parse' [ ( \"Year\", 'FoDate' "%Y" ) ] ]+  . 'dataRow' [ ( \"Animal\", 'Str' \"Fish\" ), ( \"Age\", 'Number' 28 ), ( \"Year\", 'Str' "2010" ) ]+  . 'dataRow' [ ( \"Animal\", 'Str' \"Dog\" ), ( \"Age\", 'Number' 12 ), ( \"Year\", 'Str' "2014" ) ]+  . 'dataRow' [ ( \"Animal\", 'Str' \"Cat\" ), ( \"Age\", 'Number' 6 ), ( \"Year\", 'Str' "2015" ) ]+@+-}+dataFromRows ::+  [Format]+  -- ^ An optional list of formatting instructions for the rows.+  --+  --   Simple numbers and strings do not normally need formatting, but it is+  --   good practice to explicitly declare date-time formats as handling of+  --   these values can vary between different viewers (e.g. browsers).+  --+  --   See the+  --   <https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>+  --   for more details.+  -> [DataRow]+  -- ^ The rows to add. This is expected to be created with one or more+  --   calls to 'dataRow'.+  -> Data+dataFromRows fmts rows =+  let kvs = ("values", toJSON rows)+            : if null fmts+              then []+              else [("format", object (concatMap formatProperty fmts))]+  in (VLData, object kvs)+++{-|++Declare data from a named source. The source may be from named 'datasets' within+a specification or a named data source created via the+<https://vega.github.io/vega/docs/api/view/#data Vega View API>.+An optional list of field formatting instructions can be provided as the second+parameter or an empty list to use the default formatting. See the+<https://vega.github.io/vega-lite/docs/data.html#named Vega-Lite documentation>+for details.++@+'Graphics.Vega.VegaLite.toVegaLite'+    [ 'datasets' [ ( "myData", dvals [] ),  ( "myJson", 'dataFromJson' json [] ) ]+    , 'dataFromSource' "myData" []+    , 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Bar' []+    , ...+    ]+@+-}+dataFromSource :: T.Text -> [Format] -> Data+dataFromSource sourceName fmts =+  let kvs = ("name" .= sourceName)+            : if null fmts+              then []+              else [("format", object (concatMap formatProperty fmts))]+  in (VLData, object kvs)+++{-|++Declare data source from a url. The url can be a local path on a web server+or an external http(s) url. Used to create a data ( property, specification ) pair.+An optional list of field formatting instructions can be provided as the second+parameter or an empty list to use the default formatting. See the+<https://vega.github.io/vega-lite/docs/data.html#format Vega-Lite documentation>+for details.++@+'dataFromUrl' "data/weather.csv" [ 'Parse' [ ( "date", 'FoDate' "%Y-%m-%d %H:%M" ) ] ]+@+-}+-- TODO: should this use a URL type?+dataFromUrl :: T.Text -> [Format] -> Data+dataFromUrl url fmts =+  let kvs = ("url" .= url)+            : if null fmts+              then []+              else [("format", object (concatMap formatProperty fmts))]+  in (VLData, object kvs)+++{-|++Generate a sequence of numbers as a data source. The resulting+sequence will have the name @\"data\"@. To give it an alternative name use+'dataSequenceAs'.++@+myData = 'dataSequence' 0 6.28 0.1+@++@since 0.4.0.0++-}+dataSequence ::+  Double     -- ^ start of the sequence (inclusive)+  -> Double  -- ^ end of the sequence (exclusive)+  -> Double  -- ^ step size+  -> Data+dataSequence start stop step =+  let vals = [("sequence", object svals)]+      svals = [ "start" .= start+              , "stop" .= stop+              , "step" .= step+              ]++  in (VLData, object vals)+++{-|++Generate a sequence of numbers as a named data source. This extends+'dataSequence' by allowing you to name the data source.++@+myTheta = 'dataSequenceAs' 0 6.28 0.1 \"theta\"+@++@since 0.4.0.0++-}+dataSequenceAs ::+  Double     -- ^ start of the sequence (inclusive)+  -> Double  -- ^ end of the sequence (exclusive)+  -> Double  -- ^ step size+  -> FieldName  -- ^ The name of the data source+  -> Data+dataSequenceAs start stop step outName =+  let vals = [ "sequence" .= object svals ]+      svals = [ "start" .= start+              , "stop" .= stop+              , "step" .= step+              , "as" .= outName+              ]++  in (VLData, object vals)
+ src/Graphics/Vega/VegaLite/Legend.hs view
@@ -0,0 +1,512 @@+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Legend+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : OverloadedStrings++Types for legends.++-}++module Graphics.Vega.VegaLite.Legend+       ( LegendType(..)+       , LegendOrientation(..)+       , LegendLayout(..)+       , BaseLegendLayout(..)+       , LegendProperty(..)+       , LegendValues(..)++         -- not for external export+       , legendProp_+       , legendOrientLabel+       , legendLayoutSpec++       ) where++import qualified Data.Aeson as A+import qualified Data.Text as T++import Data.Aeson ((.=), object, toJSON)++import Graphics.Vega.VegaLite.Foundation+  ( APosition+  , Bounds+  , Color+  , CompositionAlignment+  , DashStyle+  , DashOffset+  , FontWeight+  , HAlign+  , Opacity+  , Orientation+  , OverlapStrategy+  , Side+  , Symbol+  , VAlign+  , ZIndex+  , anchorLabel+  , boundsSpec+  , compositionAlignmentSpec+  , fontWeightSpec+  , hAlignLabel+  , orientationSpec+  , overlapStrategyLabel+  , sideLabel+  , symbolLabel+  , vAlignLabel++  , fromT+  , fromColor+  , fromDS+  , splitOnNewline+  )+import Graphics.Vega.VegaLite.Specification (VLSpec, LabelledSpec)+import Graphics.Vega.VegaLite.Time+  ( DateTime+  , dateTimeProperty+  )+++-- | Indicates the type of legend to create. It is used with 'LType'.+--+--   Prior to version @0.4.0.0.0@ this was called @Legend@ and the+--   constructors did not end in @Legend@.+--+data LegendType+    = GradientLegend+      -- ^ Typically used for continuous quantitative data.+    | SymbolLegend+      -- ^ Typically used for categorical data.+++legendLabel :: LegendType -> T.Text+legendLabel GradientLegend = "gradient"+legendLabel SymbolLegend = "symbol"+++{-|++Indicates the legend orientation. See the+<https://vega.github.io/vega-lite/docs/legend.html#config Vega-Lite documentation>+for more details.++-}++-- based on schema 3.3.0 #/definitions/LegendOrient++data LegendOrientation+  = LONone+  | LOLeft+  | LORight+  | LOTop+  -- ^ @since 0.4.0.0+  | LOBottom+  -- ^ @since 0.4.0.0+  | LOTopLeft+  | LOTopRight+  | LOBottomLeft+  | LOBottomRight+++legendOrientLabel :: LegendOrientation -> T.Text+legendOrientLabel LONone = "none"+legendOrientLabel LOLeft = "left"+legendOrientLabel LORight = "right"+legendOrientLabel LOTop = "top"+legendOrientLabel LOBottom = "bottom"+legendOrientLabel LOTopLeft = "top-left"+legendOrientLabel LOTopRight = "top-right"+legendOrientLabel LOBottomLeft = "bottom-left"+legendOrientLabel LOBottomRight = "bottom-right"+++{- |++/Highly experimental/ and used with 'Graphics.Vega.VegaLite.LeLayout'.++@since 0.4.0.0++-}++-- based on schema 3.3.0 #/definitions/LegendLayout++-- TODO: support SignalRef?++data LegendLayout+  = LeLAnchor APosition+    -- ^ The anchor point for legend orient group layout.+  | LeLBottom [BaseLegendLayout]+  | LeLBottomLeft [BaseLegendLayout]+  | LeLBottomRight [BaseLegendLayout]+  | LeLBounds Bounds+    -- ^ The bounds calculation to use for legend orient group layout.+  | LeLCenter Bool+    -- ^ A flag to center legends within a shared orient group.+  | LeLDirection Orientation+    -- ^ The layout firection for legend orient group layout.+  | LeLLeft [BaseLegendLayout]+  | LeLMargin Double+    -- ^ The margin, in pixels, between legends within an orient group.+  | LeLOffset Double+    -- ^ The offset, in pixels, from the chart body for a legend orient group.+  | LeLRight [BaseLegendLayout]+  | LeLTop [BaseLegendLayout]+  | LeLTopLeft [BaseLegendLayout]+  | LeLTopRight [BaseLegendLayout]+++legendLayoutSpec :: LegendLayout -> LabelledSpec+legendLayoutSpec (LeLAnchor anc) = "anchor" .= anchorLabel anc+legendLayoutSpec (LeLBottom bl) = "bottom" .= toBLSpec bl+legendLayoutSpec (LeLBottomLeft bl) = "bottom-left" .= toBLSpec bl+legendLayoutSpec (LeLBottomRight bl) = "bottom-right" .= toBLSpec bl+legendLayoutSpec (LeLBounds bnds) = "bounds" .= boundsSpec bnds+legendLayoutSpec (LeLCenter b) = "center" .= b+legendLayoutSpec (LeLDirection o) = "direction" .= orientationSpec o+legendLayoutSpec (LeLLeft bl) = "left" .= toBLSpec bl+legendLayoutSpec (LeLMargin x) = "margin" .= x+legendLayoutSpec (LeLOffset x) = "offset" .= x+legendLayoutSpec (LeLRight bl) = "right" .= toBLSpec bl+legendLayoutSpec (LeLTop bl) = "top" .= toBLSpec bl+legendLayoutSpec (LeLTopLeft bl) = "top-left" .= toBLSpec bl+legendLayoutSpec (LeLTopRight bl) = "top-right" .= toBLSpec bl+++{- |++/Highly experimental/ and used with constructors from 'LegendLayout'.++@since 0.4.0.0++-}++-- based on schema 3.3.0 #/definitions/BaseLegendLayout++data BaseLegendLayout+  = BLeLAnchor APosition+    -- ^ The anchor point for legend orient group layout.+  | BLeLBounds Bounds+    -- ^ The bounds calculation to use for legend orient group layout.+  | BLeLCenter Bool+    -- ^ A flag to center legends within a shared orient group.+  | BLeLDirection Orientation+    -- ^ The layout direction for legend orient group layout.+  | BLeLMargin Double+    -- ^ The margin, in pixels, between legends within an orient group.+  | BLeLOffset Double+    -- ^ The offset, in pixels, from the chart body for a legend orient group.+++toBLSpec :: [BaseLegendLayout] -> VLSpec+toBLSpec = object . map baseLegendLayoutSpec++baseLegendLayoutSpec :: BaseLegendLayout -> LabelledSpec+baseLegendLayoutSpec (BLeLAnchor anc) = "anchor" .= anchorLabel anc+baseLegendLayoutSpec (BLeLBounds bnds) = "bounds" .= boundsSpec bnds+baseLegendLayoutSpec (BLeLCenter b) = "center" .= b+baseLegendLayoutSpec (BLeLDirection o) = "direction" .= orientationSpec o+baseLegendLayoutSpec (BLeLMargin x) = "margin" .= x+baseLegendLayoutSpec (BLeLOffset x) = "offset" .= x+++{-|++Legend properties, set with 'Graphics.Vega.VegaLite.MLegend'. For more detail see the+<https://vega.github.io/vega-lite/docs/legend.html#legend-properties Vega-Lite documentation>.++The @LEntryPadding@ constructor was removed in @0.4.0.0@.++-}++data LegendProperty+    = LClipHeight Double+      -- ^ The height, in pixels, to clip symbol legend entries.+      --+      --   @since 0.4.0.0+    | LColumnPadding Double+      -- ^ The horizontal padding, in pixels, between symbol legend entries.+      --+      --   @since 0.4.0.0+    | LColumns Int+      -- ^ The number of columns in which to arrange symbol legend entries.+      --   A value of @0@ or lower indicates a single row with one column per entry.+      --+      --   @since 0.4.0.0+    | LCornerRadius Double+      -- ^ The corner radius for the full legend.+      --+      --   @since 0.4.0.0+    | LDirection Orientation+      -- ^ The direction of the legend.+      --+      --   @since 0.4.0.0+    | LFillColor Color+      -- ^ The background fill color for the full legend.+      --+      --   @since 0.4.0.0+    | LFormat T.Text+      -- ^ [Formatting pattern](https://vega.github.io/vega-lite/docs/format.html) for+      --   legend values. To distinguish between formatting as numeric values+      --   and data/time values, additionally use 'LFormatAsNum' or 'LFormatAsTemporal'.+    | LFormatAsNum+      -- ^ Legends should be formatted as numbers. Use a+      --   [d3 numeric format string](https://github.com/d3/d3-format#locale_format)+      --   with 'LFormat'.+      --+      -- @since 0.4.0.0+    | LFormatAsTemporal+      -- ^ Legends should be formatted as dates or times. Use a+      --   [d3 date/time format string](https://github.com/d3/d3-time-format#locale_format)+      --   with 'LFormat'.+      --+      -- @since 0.4.0.0+    | LGradientLength Double+      -- ^ The length in pixels of the primary axis of the color gradient.+      --+      --   @since 0.4.0.0+    | LGradientOpacity Opacity+      -- ^ The opacity of the color gradient.+      --+      --   @since 0.4.0.0+    | LGradientStrokeColor Color+      -- ^ The color of the gradient stroke.+      --+      --   @since 0.4.0.0+    | LGradientStrokeWidth Double+      -- ^ The width, in pixels, of the gradient stroke.+      --+      --   @since 0.4.0.0+    | LGradientThickness Double+      -- ^ The thickness, in pixels, of the color gradient.+      --+      --   @since 0.4.0.0+    | LGridAlign CompositionAlignment+      -- ^ The [grid layout](https://vega.github.io/vega/docs/layout) for+      --   the symbol legends.+      --+      --   @since 0.4.0.0+    | LLabelAlign HAlign+      -- ^ @since 0.4.0.0+    | LLabelBaseline VAlign+      -- ^ @since 0.4.0.0+    | LLabelColor Color+      -- ^ @since 0.4.0.0+    | LLabelFont T.Text+      -- ^ @since 0.4.0.0+    | LLabelFontSize Double+      -- ^ @since 0.4.0.0+    | LLabelFontStyle T.Text+      -- ^ @since 0.4.0.0+    | LLabelFontWeight FontWeight+      -- ^ @since 0.4.0.0+    | LLabelLimit Double+      -- ^ @since 0.4.0.0+    | LLabelOffset Double+      -- ^ @since 0.4.0.0+    | LLabelOpacity Opacity+      -- ^ @since 0.4.0.0+    | LLabelOverlap OverlapStrategy+      -- ^ @since 0.4.0.0+    | LLabelPadding Double+      -- ^ @since 0.4.0.0+    | LLabelSeparation Double+      -- ^ @since 0.4.0.0+    | LOffset Double+      -- ^ The offset in pixels by which to displace the legend from+      --   the data rectangle and axes.+    | LOrient LegendOrientation+      -- ^ The legend orientation.+    | LPadding Double+      -- ^ The padding, in pixels, between the border and content of+      --   the legend group.+    | LRowPadding Double+      -- ^ The vertical padding, in pixels, between symbol legend entries.+      --+      --   @since 0.4.0.0+    | LStrokeColor Color+      -- ^ The border stroke color for the full legend.+      --+      --   @since 0.4.0.0+    | LSymbolDash DashStyle+      -- ^ The dash pattern for symbols.+      --+      --   @since 0.4.0.0+    | LSymbolDashOffset DashOffset+      -- ^ The offset for the dash pattern.+      --+      --   @since 0.4.0.0+    | LSymbolFillColor Color+      -- ^ The fill color of the legend symbol.+      --+      --   @since 0.4.0.0+    | LSymbolOffset Double+      -- ^ The horizontal pixel offset for legend symbols.+      --+      --   @since 0.4.0.0+    | LSymbolOpacity Opacity+      -- ^ The opacity of the legend symbols.+      --+      --   @since 0.4.0.0+    | LSymbolSize Double+      -- ^ The size of the legend symbol, in pixels.+      --+      --   @since 0.4.0.0+    | LSymbolStrokeColor Color+      -- ^ The edge color of the legend symbol.+      --+      --   @since 0.4.0.0+    | LSymbolStrokeWidth Double+      -- ^ The width of the sumbol's stroke.+      --+      --   @since 0.4.0.0+    | LSymbolType Symbol+      -- ^ @since 0.4.0.0+    | LTickCount Double+      -- ^ The desired number of tick values for quantitative legends.+    | LTickMinStep Double+      -- ^ The minimum desired step between legend ticks, in terms of the scale+      --   domain values.+      --+      --   @since 0.4.0.0+    | LTitle T.Text+    | LNoTitle+      -- ^ Draw no title.+      --+      -- @since 0.4.0.0+    | LTitleAlign HAlign+      -- ^ @since 0.4.0.0+    | LTitleAnchor APosition+      -- ^ @since 0.4.0.0+    | LTitleBaseline VAlign+      -- ^ @since 0.4.0.0+    | LTitleColor Color+      -- ^ @since 0.4.0.0+    | LTitleFont T.Text+      -- ^ @since 0.4.0.0+    | LTitleFontSize Double+      -- ^ @since 0.4.0.0+    | LTitleFontStyle T.Text+      -- ^ @since 0.4.0.0+    | LTitleFontWeight FontWeight+      -- ^ @since 0.4.0.0+    | LTitleLimit Double+      -- ^ The maximum allowed pixel width of the legend title.+      --+      --   @since 0.4.0.0+    | LTitleOpacity Opacity+      -- ^ Opacity of the legend title.+      --+      --   @since 0.4.0.0+    | LTitleOrient Side+      -- ^ Orientation of the legend title.+      --+      --   @since 0.4.0.0+    | LTitlePadding Double+      -- ^ The padding, in pixels, between title and legend.+      --+      --   @since 0.4.0.0+    | LType LegendType+      -- ^ The type of the legend.+    | LValues LegendValues+      -- ^ Explicitly set the visible legend values.+    | LeX Double+      -- ^ Custom x position, in pixels, for the legend when 'LOrient' is set to 'LONone'.+      --+      --   @since 0.4.0.0+    | LeY Double+      -- ^ Custom y position, in pixels, for the legend when 'LOrient' is set to 'LONone'.+      --+      --   @since 0.4.0.0+    | LZIndex ZIndex+      -- ^ The z-index at which to draw the legend.++legendProperty :: LegendProperty -> LabelledSpec+legendProperty (LClipHeight x) = "clipHeight" .= x+legendProperty (LColumnPadding x) = "columnPadding" .= x+legendProperty (LColumns n) = "columns" .= n+legendProperty (LCornerRadius x) = "cornerRadius" .= x+legendProperty (LDirection o) = "direction" .= orientationSpec o+legendProperty (LFillColor s) = "fillColor" .= fromColor s+legendProperty (LFormat s) = "format" .= s+legendProperty LFormatAsNum = "formatType" .= fromT "number"+legendProperty LFormatAsTemporal = "formatType" .= fromT "time"+legendProperty (LGradientLength x) = "gradientLength" .= x+legendProperty (LGradientOpacity x) = "gradientOpacity" .= x+legendProperty (LGradientStrokeColor s) = "gradientStrokeColor" .= fromColor s+legendProperty (LGradientStrokeWidth x) = "gradientStrokeWidth" .= x+legendProperty (LGradientThickness x) = "gradientThickness" .= x+legendProperty (LGridAlign ga) = "gridAlign" .= compositionAlignmentSpec ga+legendProperty (LLabelAlign ha) = "labelAlign" .= hAlignLabel ha+legendProperty (LLabelBaseline va) = "labelBaseline" .= vAlignLabel va+legendProperty (LLabelColor s) = "labelColor" .= fromColor s+legendProperty (LLabelFont s) = "labelFont" .= s+legendProperty (LLabelFontSize x) = "labelFontSize" .= x+legendProperty (LLabelFontStyle s) = "labelFontStyle" .= s+legendProperty (LLabelFontWeight fw) = "labelFontWeight" .= fontWeightSpec fw+legendProperty (LLabelLimit x) = "labelLimit" .= x+legendProperty (LLabelOffset x) = "labelOffset" .= x+legendProperty (LLabelOpacity x) = "labelOpacity" .= x+legendProperty (LLabelOverlap strat) = "labelOverlap" .= overlapStrategyLabel strat+legendProperty (LLabelPadding x) = "labelPadding" .= x+legendProperty (LLabelSeparation x) = "labelSeparation" .= x+legendProperty (LOffset x) = "offset" .= x+legendProperty (LOrient orl) = "orient" .= legendOrientLabel orl+legendProperty (LPadding x) = "padding" .= x+legendProperty (LRowPadding x) = "rowPadding" .= x+legendProperty (LStrokeColor s) = "strokeColor" .= fromColor s++legendProperty (LSymbolDash ds) = "symbolDash" .= fromDS ds+legendProperty (LSymbolDashOffset x) = "symbolDashOffset" .= x+legendProperty (LSymbolFillColor s) = "symbolFillColor" .= fromColor s+legendProperty (LSymbolOffset x) = "symbolOffset" .= x+legendProperty (LSymbolOpacity x) = "symbolOpacity" .= x+legendProperty (LSymbolSize x) = "symbolSize" .= x+legendProperty (LSymbolStrokeColor s) = "symbolStrokeColor" .= fromColor s+legendProperty (LSymbolStrokeWidth x) = "symbolStrokeWidth" .= x+legendProperty (LSymbolType sym) = "symbolType" .= symbolLabel sym+legendProperty (LTickCount x) = "tickCount" .= x+legendProperty (LTickMinStep x) = "tickMinStep" .= x+legendProperty (LTitle s) = "title" .= splitOnNewline s+legendProperty LNoTitle = "title" .= A.Null+legendProperty (LTitleAlign ha) = "titleAlign" .= hAlignLabel ha+legendProperty (LTitleAnchor anc) = "titleAnchor" .= anchorLabel anc+legendProperty (LTitleBaseline va) = "titleBaseline" .= vAlignLabel va+legendProperty (LTitleColor s) = "titleColor" .= fromColor s+legendProperty (LTitleFont s) = "titleFont" .= s+legendProperty (LTitleFontSize x) = "titleFontSize" .= x+legendProperty (LTitleFontStyle s) = "titleFontStyle" .= s+legendProperty (LTitleFontWeight fw) = "titleFontWeight" .= fontWeightSpec fw+legendProperty (LTitleLimit x) = "titleLimit" .= x+legendProperty (LTitleOpacity x) = "titleOpacity" .= x+legendProperty (LTitleOrient orient) = "titleOrient" .= sideLabel orient+legendProperty (LTitlePadding x) = "titlePadding" .= x+legendProperty (LType lType) = "type" .= legendLabel lType+legendProperty (LValues vals) =+  let ls = case vals of+        LNumbers xs    -> map toJSON xs+        LDateTimes dts -> map (object . map dateTimeProperty) dts+        LStrings ss    -> map toJSON ss+  in "values" .= ls+legendProperty (LeX x) = "legendX" .= x+legendProperty (LeY x) = "legendY" .= x+legendProperty (LZIndex z) = "zindex" .= z+++legendProp_ :: [LegendProperty] -> LabelledSpec+legendProp_ [] = "legend" .= A.Null+legendProp_ lps = "legend" .= object (map legendProperty lps)+++-- | A list of data values suitable for setting legend values, used with+--   'LValues'.+++data LegendValues+    = LDateTimes [[DateTime]]+    | LNumbers [Double]+    | LStrings [T.Text]
+ src/Graphics/Vega/VegaLite/Mark.hs view
@@ -0,0 +1,980 @@+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Mark+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : OverloadedStrings++This provides the functionality of the VegaLite module but is+not directly exported to the user.++-}++module Graphics.Vega.VegaLite.Mark+       ( Mark(..)+       , MarkProperty(..)+       , MarkInterpolation(..)+       , PointMarker(..)+       , LineMarker(..)+       , MarkErrorExtent(..)+       , GradientCoord+       , GradientStops+       , ColorGradient(..)+       , GradientProperty(..)+       , TextDirection(..)++         -- not for external export+       , mprops_++       , markLabel+       , markProperty++       ) where++import qualified Data.Aeson as A+import qualified Data.Text as T++import Data.Aeson ((.=), object, toJSON)+import Data.List (sortOn)+++import Graphics.Vega.VegaLite.Foundation+  ( Angle+  , Color+  , DashStyle+  , DashOffset+  , Cursor+  , FontWeight+  , Opacity+  , Orientation+  , StrokeCap+  , StrokeJoin+  , Symbol+  , TooltipContent(TTNone)+  , HAlign+  , VAlign+  , fromColor+  , fromDS+  , cursorLabel+  , fontWeightSpec+  , orientationSpec+  , strokeCapLabel+  , strokeJoinLabel+  , symbolLabel+  , ttContentLabel+  , hAlignLabel+  , vAlignLabel+  )+import Graphics.Vega.VegaLite.Specification+  ( VLSpec+  , LabelledSpec+  )+++-- TODO: should this turn an empty list into true?+mprops_ :: T.Text -> [MarkProperty] -> LabelledSpec+mprops_ f mps = f .= object (map markProperty mps)+++-- | Type of visual mark used to represent data in the visualization.+--+--   The properties of the mark can be changed with the 'MarkProperty'+--   constructors - such as 'MHeight' and 'MWidth' -  although not all+--   properties apply to all marks.+--+data Mark+    = Area+      -- ^ An [area mark](https://vega.github.io/vega-lite/docs/area.html)+      --   for representing a series of data elements, such as in a stacked+      --   area chart or streamgraph.+    | Bar+      -- ^ [Bar mark](https://vega.github.io/vega-lite/docs/bar.html)+      --   for histograms, bar charts etc.+    | Boxplot+      -- ^ [Boxplot composite mark](https://vega.github.io/vega-lite/docs/boxplot.html)+      --   for showing summaries of statistical distributions.+      --+      --   Tick marks can be added using 'MTicks' and outliers turned+      --   off with 'MNoOutliers' or configured with 'MOutliers'.+      --   For example:+      --+      --   @+      --   'Graphics.Vega.VegaLite.mark' Boxplot+      --       [ 'MTicks' [ 'MColor' \"black\", 'MSize' 8 ]+      --       , 'MBox' [ 'MFill' \"grey\" ]+      --       , 'MOutliers' [ 'MColor' \"firebrick\" ]+      --   ]+      --   @+      --+      --   The range of the box plot is controlled with 'MExtent' with+      --   the 'IqrScale' or 'ExRange' options (the default is+      --   @IqrScale 1.5@).+      --+      --   @since 0.4.0.0+    | Circle+      -- ^ [Circle mark](https://vega.github.io/vega-lite/docs/circle.html)+      --   for representing points.+    | ErrorBar+      -- ^ [Errorbar composite mark](https://vega.github.io/vega-lite/docs/errorbar.html)+      --   for showing summaries of variation along a signal. By default+      --   no ticks are drawn. To add ticks with default properties use+      --   @`MTicks` []@, otherwise supply a list of configuration options:+      --+      --   @+      --   'Graphics.Vega.VegaLite.mark' ErrorBar [ 'MTicks' [ 'MColor' \"black\", 'MSize' 8 ] ]+      --   @+      --+      --   @since 0.4.0.0+    | ErrorBand+      -- ^ [Errorband composite mark](https://vega.github.io/vega-lite/docs/errorband.html)+      --   for showing summaries of variation along a signal. By default+      --   no border is drawn. To add a border with default properties use+      --   @'MBorders' []@, otherwise supply a list of configuration options:+      --+      --   @+      --   'Graphics.Vega.VegaLite.mark' ErrorBand [ 'MBorders' [ 'MColor' \"black\", 'MStrokeWidth' 0.5 ] ]+      --   @+      --+      --   @since 0.4.0.0+    | Geoshape+      -- ^ [Geoshape](https://vega.github.io/vega-lite/docs/geoshape.html)+      --   determined by geographically referenced coordinates.+    | Image+      -- ^ [Vega Lite image mark](https://vega.github.io/vega-lite/docs/image.html),+      --   where the image to display is given via the+      --   'Graphics.Vega.VegaLite.url' channel, and the width and height+      --   defined by the 'MWidth' and 'MHeight' properties.+      --+      --   @since 0.5.0.0+    | Line+      -- ^ [Line mark](https://vega.github.io/vega-lite/docs/line.html)+      --   for symbolising a sequence of values.+    | Point+      -- ^ [Point mark](https://vega.github.io/vega-lite/docs/point.html)+      --   for symbolising a data point with a symbol.+    | Rect+      -- ^ [Rectangle mark](https://vega.github.io/vega-lite/docs/rect.html).+    | Rule+      -- ^ [Rule line](https://vega.github.io/vega-lite/docs/rule.html)+      --   connecting two vertices.+    | Square+      -- ^ [Square mark](https://vega.github.io/vega-lite/docs/square.html)+      --   for symbolising points.+    | Text+      -- ^ [Text mark](https://vega.github.io/vega-lite/docs/text.html)+      --   to be displayed at some point location.+    | Tick+      -- ^ Short line - [tick](https://vega.github.io/vega-lite/docs/tick.html) -+      --   mark for symbolising point locations.+    | Trail+      -- ^ [Trail mark](https://vega.github.io/vega-lite/docs/trail.html)+      --   (line with variable width along its length).+      --+      --   @since 0.4.0.0+++markLabel :: Mark -> T.Text+markLabel Area = "area"+markLabel Bar = "bar"+markLabel Boxplot = "boxplot"+markLabel Circle = "circle"+markLabel ErrorBar = "errorbar"+markLabel ErrorBand = "errorband"+markLabel Line = "line"+markLabel Geoshape = "geoshape"+markLabel Image = "image"+markLabel Point = "point"+markLabel Rect = "rect"+markLabel Rule = "rule"+markLabel Square = "square"+markLabel Text = "text"+markLabel Tick = "tick"+markLabel Trail = "trail"+++{-|++Properties for customising the appearance of a mark. For details see the+<https://vega.github.io/vega-lite/docs/mark.html#config Vega-Lite documentation>.++Not all properties are valid for each mark type.++The Vega-Lite specification supports setting those properties that take+@['MarkProperty']@ also to a boolean value. This is currently not+supported in @hvega@.++In @version 0.5.0.0@ the 'MRemoveInvalid' constructor was added, which+replaces the @RemoveInvalid@ constructor of+'Graphics.Vega.VegaLite.ConfigurationProperty', and the+@MShortTimeLabels@ constuctor was removed.++-}++-- based on schema+--     #/definitions/MarkConfig+--     #/definitions/MarkDef+--     #/definitions/OverlayMarkDef+--+--     #/definitions/TickConfig+--+-- ie it conflates meaning++data MarkProperty+    = MAlign HAlign+      -- ^ Horizontal alignment of a text mark.+    | MAngle Angle+      -- ^ Rotation angle of a text mark.+    | MAspect Bool+      -- ^ Should the aspect ratio of an 'Image' mark be preserved?+      --+      --   @since 0.5.0.0+    | MBandSize Double+      -- ^ Band size of a bar mark.+    | MBaseline VAlign+      -- ^ Vertical alignment of a text mark.+    | MBinSpacing Double+      -- ^ Offset between bars for a binned field using a bar mark.+      --+      --   The ideal value for this is either @0@ (preferred by statisticians)+      --   or @1@ (the Vega-Lite default value, D3 example style).+    | MBorders [MarkProperty]+      -- ^ Border properties for an 'ErrorBand' mark.+      --+      --   @since 0.4.0.0+    | MBox [MarkProperty]+      -- ^ Box-symbol properties for a 'Boxplot' mark.+      --+      --   @since 0.4.0.0+    | MClip Bool+      -- ^ Should a mark be clipped to the enclosing group's dimensions.+    | MColor Color+      -- ^ Default color of a mark. Note that 'MFill' and 'MStroke' have higher+      --   precedence and will override this if specified.+    | MColorGradient ColorGradient GradientStops [GradientProperty]+      -- ^ The color gradient to apply to a mark. The first argument+      --   determines its type, the second is the list of color+      --   interpolation points, and the third+      --   allows for customization.+      --+      --   @+      --   'MColorGradient'+      --       'GrRadial'+      --       [ ( 0, \"red\" ), ( 1, \"blue\" ) ]+      --       [ ]+      --   @+      --+      --   @since 0.5.0.0+    | MCornerRadius Double+      -- ^ Corner radius of all corners of a rectangular mark, in pixels.+      --+      --   The default is 0. This value is over-ridden by any of+      --   'MCornerRadiusTL', 'MCornerRadiusTR', 'MCornerRadiusBL',+      --   or 'MCornerRadiusBR'.+      --+      --   @since 0.5.0.0+    | MCornerRadiusTL Double+      -- ^ Top-left corner radius of a rectangular mark, in pixels.+      --+      --   The default is 0.+      --+      --   @since 0.5.0.0+    | MCornerRadiusTR Double+      -- ^ Top-right corner radius of a rectangular mark, in pixels.+      --+      --   The default is 0.+      --+      --   @since 0.5.0.0+    | MCornerRadiusBL Double+      -- ^ Bottom-left corner radius of a rectangular mark, in pixels.+      --+      --   The default is 0.+      --+      --   @since 0.5.0.0+    | MCornerRadiusBR Double+      -- ^ Bottom-right corner radius of a rectangular mark, in pixels.+      --+      --   The default is 0.+      --+      --   @since 0.5.0.0+    | MCursor Cursor+      -- ^ Cursor to be associated with a hyperlink mark.+    | MDir TextDirection+      -- ^ Direction of the text. This property determines which side of the+      --   label is truncated by the 'MLimit' parameter. See also 'MEllipsis'.+      --+      --   The default is 'LTR'.+      --+      --   @since 0.5.0.0+    | MContinuousBandSize Double+      -- ^ Continuous band size of a bar mark.+    | MDiscreteBandSize Double+      -- ^ Discrete band size of a bar mark.+    | MdX Double+      -- ^ Horizontal offset between a text mark and its anchor.+    | MdY Double+      -- ^ Vertical offset between a text mark and its anchor.+    | MEllipsis T.Text+      -- ^ The ellipsis string for text truncated in response to+      --   'MLimit'. See also 'MDir'.+      --+      --   The default is @\"…\"@.+      --+      --   @since 0.5.0.0+    | MExtent MarkErrorExtent+      -- ^ Extent of whiskers used with 'Boxplot', 'ErrorBar', and+      --   'ErrorBand' marks.+      --+      --   @since 0.4.0.0+    | MFill Color+      -- ^ Default fill color of a mark.+      --+      --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    | MFilled Bool+      -- ^ Should a mark's color should be used as the fill color instead of+      --   stroke color.+    | MFillGradient ColorGradient GradientStops [GradientProperty]+      -- ^ The color gradient to apply to the interior of a mark. The first argument+      --   determines its type, the second is the list of color+      --   interpolation points, and the third+      --   allows for customization.+      --+      --   @+      --   'MFillGradient'+      --       'GrLinear'+      --       [ ( 0, \"orange\" ), ( 1, \"green\" ) ]+      --       [ ]+      --   @+      --+      --   @since 0.5.0.0+    | MFillOpacity Opacity+      -- ^ Fill opacity of a mark.+    | MFont T.Text+      -- ^ Font of a text mark. Can be any font name made accessible via+      -- a css file (or a generic font like \"serif\", \"monospace\" etc.).+    | MFontSize Double+      -- ^ Font size, in pixels, used by a text mark.+    | MFontStyle T.Text+      -- ^ Font style (e.g. \"italic\") used by a text mark.+    | MFontWeight FontWeight+      -- ^ Font weight used by a text mark.+    | MHeight Double+      -- ^ Explicitly set the height of a mark. See also 'MWidth'.+      --+      --   @since 0.4.0.0+    | MHRef T.Text+      -- ^ Hyperlink to be associated with a mark making it a clickable+      --   hyperlink.+      --+      --   @since 0.4.0.0+    | MInterpolate MarkInterpolation+      -- ^ Interpolation method used by line and area marks.+    | MLimit Double+      -- ^ The maximum length of the text mark in pixels. If the text is+      --   larger then it will be truncated, with the truncation controlled+      --   by 'MEllipsis' and 'MDir'.+      --+      --   The default value is @0@, which indicates no truncation.+      --+      --   @since 0.5.0.0+    | MLine LineMarker+      -- ^ How should the vertices of an area mark be joined?+      --+      --   @since 0.4.0.0+    | MLineBreak T.Text+      -- ^ A delimeter, such as a newline character, upon which to break+      --   text strings into multiple lines.+      --+      --   Note that @hvega@ automatically breaks text on the @\\n@ character,+      --   which will over-ride this setting. Therefore setting this only+      --   makes sense if the text does not contain @\n@ characters.+      --+      --   @since 0.5.0.0+    | MLineHeight Double+      -- ^ The height, in pixels, of each line of text in a multi-line text mark.+      --+      --   @since 0.5.0.0+    | MMedian [MarkProperty]+      -- ^ Median-line properties for the 'Boxplot' mark.+      --+      --   @since 0.4.0.0+    | MOpacity Opacity+      -- ^ Overall opacity of a mark in the range 0 to 1.+    | MOrder Bool+      -- ^ Ordering of vertices in a line or area mark. If @True@ (the default),+      --   the order is determined by measurement type or order channel. If+      --   @False@, the original data order is used.+      --+      --   @since 0.4.0.0+    | MOrient Orientation+      -- ^ Orientation of a non-stacked bar, tick, area or line mark.+    | MOutliers [MarkProperty]+      -- ^ Outlier symbol properties for the 'Boxplot' mark.+      --+      --   @since 0.4.0.0+    | MNoOutliers+      -- ^ Do not draw outliers with the 'Boxplot' mark.+      --+      --   @since 0.4.0.0+    | MPoint PointMarker+      -- ^ Appearance of a point marker joining the vertices of a line or area mark.+      --+      --   @since 0.4.0.0+    | MRadius Double+      -- ^ Polar coordinate radial offset of a text mark from its origin.+    | MRemoveInvalid Bool+      -- ^ The default handling of invalid (@null@ and @NaN@) values. If @True@,+      --   invalid values are skipped or filtered out when represented as marks,+      --   otherwise they are taken to be @0@.+      --+      --   This replaces @RemoveInvalid@ from+      --   'Graphics.Vega.VegaLite.ConfigurationProperty'+      --   in version 0.4 of @hvega@.+      --+      --   @since 0.5.0.0+    | MRule [MarkProperty]+      -- ^ Rule (main line) properties for the 'ErrorBar' and 'Boxplot' marks.+      --+      --   @since 0.4.0.0+    | MShape Symbol+      -- ^ Shape of a point mark.+    | MSize Double+      -- ^ Size of a mark.+    | MStroke Color+      -- ^ Default stroke color of a mark.+      --+      --   This was changed to use the @Color@ type alias in version @0.5.0.0@.+    | MStrokeCap StrokeCap+      -- ^ Cap style of a mark's stroke.+      --+      --   @since 0.4.0.0+    | MStrokeDash DashStyle+      -- ^ The stroke dash pattern used by a mark.+    | MStrokeDashOffset DashOffset+      -- ^ The offset for the dash pattern.+    | MStrokeGradient ColorGradient GradientStops [GradientProperty]+      -- ^ The color gradient to apply to the boundary of a mark. The first argument+      --   determines its type, the second is the list of color+      --   interpolation points, and the third+      --   allows for customization.+      --+      --   @+      --   'MStrokeGradient'+      --       'GrLinear'+      --       [ ( 0, \"pink\" ), ( 1, \"violet\" ) ]+      --       [ ]+      --   @+      --+      --   @since 0.5.0.0+    | MStrokeJoin StrokeJoin+      -- ^ Line segment join style of a mark's stroke.+      --+      --   @since 0.4.0.0+    | MStrokeMiterLimit Double+      -- ^ Mitre limit at which to bevel a join between line segments of a+      --   mark's stroke.+      --+      --   @since 0.4.0.0+    | MStrokeOpacity Opacity+      -- ^ Stroke opacity of a mark in the range 0 to 1.+    | MStrokeWidth Double+      -- ^ Stroke width of a mark in pixels.+    | MStyle [T.Text]+      -- ^ Names of custom styles to apply to a mark. Each should refer to a named style+      --   defined in a separate style configuration.+    | MTension Double+      -- ^ Interpolation tension used when interpolating line and area marks.+    | MText T.Text+      -- ^ Placeholder text for a text mark for when a text channel is not specified.+    | MTheta Double+      -- ^ Polar coordinate angle (clockwise from north in radians)+      --   of a text mark from the origin (determined by its+      --   x and y properties).+    | MThickness Double+      -- ^ Thickness of a tick mark.+    | MTicks [MarkProperty]+      -- ^ Tick properties for the 'ErrorBar' or 'Boxplot' mark.+      --+      --   @since 0.4.0.0+    | MTimeUnitBand Double+      -- ^ The default relative band size for a time unit.+      --+      --   If set to 1 the bandwidth of the marks will be equal to the time unit band step,+      --   and if set to 0.5 they will be half that.+      --+      --   @since 0.5.0.0+    | MTimeUnitBandPosition Double+      -- ^ The default relative band position for a time unit.+      --+      --   If set to 0 the marks will be positioned at the start of the band,+      --   and if set to 0.5 they will be in the middle.+      --+      --   @since 0.5.0.0+    | MTooltip TooltipContent+      -- ^ The tooltip content for a mark.+      --+      --   @since 0.4.0.0+      {- Not clear this adds anything with the current hvega design,+         since the mark function adds this field, and other places that+         MarkProperty can be used do not accept a type option+    | MType Mark+      -- ^ The mark type.+      --+      --   @since 0.5.0.0+       -}+    | MWidth Double+      -- ^ Explicitly set the width of a mark (e.g. the bar width). See also+      --   'MHeight'.+      --+      --   @since 0.4.0.0+    | MX Double+      -- ^ X position of a mark.+      --+      --   @since 0.4.0.0+    | MX2 Double+      -- ^ X2 position of a mark. This is the secondary position for+      --   lines and area marks).+      --+      --   @since 0.4.0.0+    | MXOffset Double+      -- ^ X position offset of a mark.+      --+      --   @since 0.4.0.0+    | MX2Offset Double+      -- ^ X2 position offset of a mark.+      --+      --   @since 0.4.0.0+    | MY Double+      -- ^ Y position of a mark.+      --+      --   @since 0.4.0.0+    | MY2 Double+      -- ^ Y2 position of a mark. This is the secondary position for+      --   lines and area marks).+      --+      --   @since 0.4.0.0+    | MYOffset Double+      -- ^ Y position offset of a mark.+      --+      --   @since 0.4.0.0+    | MY2Offset Double+      -- ^ Y2 position offset of a mark.+      --+      --   @since 0.4.0.0+++markProperty :: MarkProperty -> LabelledSpec++-- special case the gradients+markProperty (MColorGradient dir stops opts) =+  "color" .= gradientSpec dir stops opts+markProperty (MFillGradient dir stops opts) =+  "fill" .= gradientSpec dir stops opts+markProperty (MStrokeGradient dir stops opts) =+  "stroke" .= gradientSpec dir stops opts++-- where are these defined?+markProperty (MContinuousBandSize x) = "continuousBandSize" .= x+markProperty (MDiscreteBandSize x) = "discreteBandSize" .= x++markProperty (MAlign algn) = "align" .= hAlignLabel algn+markProperty (MAngle x) = "angle" .= x+markProperty (MAspect b) = "aspect" .= b+markProperty (MBaseline va) = "baseline" .= vAlignLabel va++-- only available in TickConfig+markProperty (MBandSize x) = "bandSize" .= x++markProperty (MBinSpacing x) = "binSpacing" .= x++-- only available in ErrorBand[Config|Def], PartsMixins<ErrorBandPart>+markProperty (MBorders mps) = mprops_ "borders" mps++-- BoxPlot[Config|Deg], PartsMixins<BoxPlotPart>+markProperty (MBox mps) = mprops_ "box" mps++markProperty (MClip b) = "clip" .= b+markProperty (MColor col) = "color" .= fromColor col+markProperty (MCornerRadius x) = "cornerRadius" .= x+markProperty (MCornerRadiusTL x) = "cornerRadiusTopLeft" .= x+markProperty (MCornerRadiusTR x) = "cornerRadiusTopRight" .= x+markProperty (MCornerRadiusBL x) = "cornerRadiusBottomLeft" .= x+markProperty (MCornerRadiusBR x) = "cornerRadiusBottomRight" .= x+markProperty (MCursor cur) = "cursor" .= cursorLabel cur+markProperty (MDir td) = "dir" .= textdirLabel td+markProperty (MdX dx) = "dx" .= dx+markProperty (MdY dy) = "dy" .= dy+markProperty (MEllipsis s) = "ellipsis" .= s++-- combo of BoxPlot[Config|Def], ErrorBand[Config|Def], ErrorBar[Config|Def]+markProperty (MExtent mee) = markErrorExtentLSpec mee++markProperty (MFill col) = "fill" .= fromColor col+markProperty (MFilled b) = "filled" .= b+markProperty (MFillOpacity x) = "fillOpacity" .= x+markProperty (MFont fnt) = "font" .= fnt+markProperty (MFontSize x) = "fontSize" .= x+markProperty (MFontStyle fSty) = "fontStyle" .= fSty+markProperty (MFontWeight w) = "fontWeight" .= fontWeightSpec w+markProperty (MHeight x) = "height" .= x+markProperty (MHRef s) = "href" .= s+markProperty (MInterpolate interp) = "interpolate" .= markInterpolationLabel interp+markProperty (MRemoveInvalid b) = "invalid" .= if b then "filter" else A.Null+markProperty (MLimit x) = "limit" .= x+markProperty (MLine lm) = "line" .= lineMarkerSpec lm+markProperty (MLineBreak s) = "lineBreak" .= s+markProperty (MLineHeight x) = "lineHeight" .= x++-- BoxPlot[Config|Def] possibly others+markProperty (MMedian mps) = mprops_ "median" mps++markProperty (MOpacity x) = "opacity" .= x+markProperty (MOrder b) = "order" .= b+markProperty (MOrient orient) = "orient" .= orientationSpec orient++-- what uses this?+markProperty (MOutliers []) = "outliers" .= True  -- TODO: should mprops_ do this?+markProperty (MOutliers mps) = mprops_ "outliers" mps+markProperty MNoOutliers = "outliers" .= False++markProperty (MPoint pm) = "point" .= pointMarkerSpec pm+markProperty (MRadius x) = "radius" .= x++-- what uses this?+markProperty (MRule mps) = mprops_ "rule" mps++markProperty (MShape sym) = "shape" .= symbolLabel sym+markProperty (MSize x) = "size" .= x+markProperty (MStroke t) = "stroke" .= fromColor t+markProperty (MStrokeCap sc) = "strokeCap" .= strokeCapLabel sc+markProperty (MStrokeDash xs) = "strokeDash" .= fromDS xs+markProperty (MStrokeDashOffset x) = "strokeDashOffset" .= x+markProperty (MStrokeJoin sj) = "strokeJoin" .= strokeJoinLabel sj+markProperty (MStrokeMiterLimit x) = "strokeMiterLimit" .= x+markProperty (MStrokeOpacity x) = "strokeOpacity" .= x+markProperty (MStrokeWidth w) = "strokeWidth" .= w+markProperty (MStyle [style]) = "style" .= style  -- special case singleton+markProperty (MStyle styles) = "style" .= styles+markProperty (MTension x) = "tension" .= x+markProperty (MText txt) = "text" .= txt+markProperty (MTheta x) = "theta" .= x+markProperty (MThickness x) = "thickness" .= x++-- what uses this?+markProperty (MTicks mps) = mprops_ "ticks" mps++markProperty (MTimeUnitBand x) = "timeUnitBand" .= x+markProperty (MTimeUnitBandPosition x) = "timeUnitBandPosition" .= x+markProperty (MTooltip TTNone) = "tooltip" .= A.Null+markProperty (MTooltip tc) = "tooltip" .= object ["content" .= ttContentLabel tc]+{-+markProperty (MType m) = "type" .= markLabel m+-}+markProperty (MWidth x) = "width" .= x+markProperty (MX x) = "x" .= x+markProperty (MY x) = "y" .= x+markProperty (MX2 x) = "x2" .= x+markProperty (MY2 x) = "y2" .= x+markProperty (MXOffset x) = "xOffset" .= x+markProperty (MYOffset x) = "yOffset" .= x+markProperty (MX2Offset x) = "x2Offset" .= x+markProperty (MY2Offset x) = "y2Offset" .= x++-- unlike elm, need to sort the stops list since we don't have a+-- smart constructor (although it's not obvious this is actually needed,+-- as I think Vega-Lite doesn't require this).+--+gradientSpec :: ColorGradient -> GradientStops -> [GradientProperty] -> VLSpec+gradientSpec dir stops props =+  let sortedStops = sortOn fst stops+  in object ([ "gradient" .= colorGradientLabel dir+             , "stops" .= map stopSpec sortedStops ]+             ++ map gradientProperty props)+++{-|++Indicates the mark interpolation style. See the+<https://vega.github.io/vega-lite/docs/mark.html#mark-def Vega-Lite documentation>+for details.+-}+data MarkInterpolation+    = Basis+      -- ^ A B-spline interpolation between points anchored at the first+      --   and last points.+    | BasisClosed+      -- ^ Closed B-spline interpolation between points forming a polygon.+    | BasisOpen+      -- ^ Open B-spline interpolation between points, which may not+      --   intersect the first and last points.+    | Bundle+      -- ^ Bundle curve interpolation between points. This is equivalent to 'Basis'+      --   except that the tension parameter is used to straighten the spline.+    | Cardinal+      -- ^ Cardinal spline interpolation between points anchored at the first+      --   and last points.+    | CardinalClosed+      -- ^ Closed Cardinal spline interpolation between points forming a polygon.+    | CardinalOpen+      -- ^ Open Cardinal spline interpolation between points, which may not+      --   intersect the first and last points.+    | Linear+      -- ^ Linear interpolation between points.+    | LinearClosed+      -- ^ Closed linear interpolaiton between points forming a polygon.+    | Monotone+      -- ^ Cubic spline interpolation that preserves monotonicity between points.+    | StepAfter+      -- ^ Piecewise (stepped) constant interpolation function after each point in a+      --   sequence.+    | StepBefore+      -- ^ Piecewise (stepped) constant interpolation function before each point in a+      --   sequence.+    | Stepwise+      -- ^ Piecewise (stepped) constant interpolation function centred on each point+      --   in a sequence.+++markInterpolationLabel :: MarkInterpolation -> T.Text+markInterpolationLabel Linear = "linear"+markInterpolationLabel LinearClosed = "linear-closed"+markInterpolationLabel Stepwise = "step"+markInterpolationLabel StepBefore = "step-before"+markInterpolationLabel StepAfter = "step-after"+markInterpolationLabel Basis = "basis"+markInterpolationLabel BasisOpen = "basis-open"+markInterpolationLabel BasisClosed = "basis-closed"+markInterpolationLabel Cardinal = "cardinal"+markInterpolationLabel CardinalOpen = "cardinal-open"+markInterpolationLabel CardinalClosed = "cardinal-closed"+markInterpolationLabel Bundle = "bundle"+markInterpolationLabel Monotone = "monotone"+++-- | The properties of a point marker on a line or area mark.+--   For use with 'MPoint'.+--+--   @since 0.4.0.0++data PointMarker+    = PMTransparent+    -- ^ A transparent marker is used, which can be useful for+    --   interactive selections.+    | PMNone+    -- ^ No marker to be shown.+    | PMMarker [MarkProperty]+    -- ^ The properties of the marks to be shown at the points.+    --+    --   Use an empty list to use a filled point with default properties.++-- An empty object has the same meaning as true, so there is no real need to+-- treat 'PMMarker []' specially, but I don't think it complicates things+-- here.+--+pointMarkerSpec :: PointMarker -> VLSpec+pointMarkerSpec PMTransparent = "transparent"+pointMarkerSpec PMNone = toJSON False+pointMarkerSpec (PMMarker []) = toJSON True+pointMarkerSpec (PMMarker mps) = object (map markProperty mps)+++{-|++Appearance of a line marker that is overlaid on an area mark.+For use with 'MLine'.++@since 0.4.0.0++-}++data LineMarker+  = LMNone+    -- ^ No line marker.+  | LMMarker [MarkProperty]+    -- ^ The properties of a line marker overlain on an area mark.+    --+    --   Use an empty list to use a filled point with default properties.+++-- An empty object has the same meaning as true, so there is no real need to+-- treat 'LMMarker []' specially, but I don't think it complicates things+-- here.+--+lineMarkerSpec :: LineMarker -> VLSpec+lineMarkerSpec LMNone = toJSON False+lineMarkerSpec (LMMarker []) = toJSON True+lineMarkerSpec (LMMarker mps) = object (map markProperty mps)+++{-|++Indicates the extent of the rule used for the error bar.  See+<https://vega.github.io/vega-lite/docs/errorbar.html#properties Vega-Lite documentation>+for details.++Note that not all options are valid for all mark types.++This is called @SummaryExtent@ in Elm and the constructors also have+different names.++@since 0.4.0.0+-}++-- based on schema 3.3.0 #/definitions/ErrorBarExtent+--          (ConfidenceInterval to Iqr)+-- and combined with the box/band "min-max" and IQR scaling values+--++data MarkErrorExtent+  = ConfidenceInterval+    -- ^ Band extent between the 95% confidence intervals of a distribution.+  | StdErr+    -- ^ Band extent as the standard error about the mean of a distribution.+  | StdDev+    -- ^ Band extent as the standard deviation of a distribution.+  | Iqr+    -- ^ Band extent between the lower and upper quartiles of a distribution+    --   (the inter-quartile range, q1 to q3).+  | ExRange+    -- ^ Band extent between the minimum and maximum values in a distribution.+  | IqrScale Double+    -- ^ A scaling of the interquartile range to be used as whiskers in a+    --   'Boxplot'. For example @IqrScale 1.5@  would extend whiskers to+    --   ±1.5x the IQR from the mean.++-- This is a little different from the other calls since I wanted to+-- make sure the scale factor was encoded as a number not a string.+--+extent_ :: T.Text -> LabelledSpec+extent_ v = "extent" .= v++markErrorExtentLSpec :: MarkErrorExtent -> LabelledSpec+markErrorExtentLSpec ConfidenceInterval = extent_ "ci"+markErrorExtentLSpec StdErr             = extent_ "stderr"+markErrorExtentLSpec StdDev             = extent_ "stdev"+markErrorExtentLSpec Iqr                = extent_ "iqr"+markErrorExtentLSpec ExRange            = extent_ "min-max"+markErrorExtentLSpec (IqrScale sc)      = "extent" .= sc+++{-|+Define the form of the+<https://vega.github.io/vega-lite/docs/types.html#gradient color gradient>+(for use with 'MColorGradient' and 'MFillGradient').++@since 0.5.0.0++-}++data ColorGradient+  = GrLinear+    -- ^ A linear gradient.+  | GrRadial+    -- ^ A radial gradient.+++colorGradientLabel :: ColorGradient -> T.Text+colorGradientLabel GrLinear = "linear"+colorGradientLabel GrRadial = "radial"+++{-|++Convenience type-annotation to label a normalized coordinate+for color gradients. The value should be in the range 0 to 1,+inclusive. There is __no attempt__ to validate that the number+lies within this range.++@since 0.5.0.0+-}+type GradientCoord = Double+++{-|++Convenience type-annotation label to indicate the color interpolation+points - i.e. the colors to use at points along the+normalized range 0 to 1 (inclusive).++The list does not have to be sorted. There is no check that the+color is valid (i.e. not empty or a valid color specification).++@since 0.5.0.0+-}+type GradientStops = [(GradientCoord, Color)]+++stopSpec :: (GradientCoord, Color) -> VLSpec+stopSpec (x, c) = object [ "offset" .= x, "color" .= fromColor c ]+++{-|++Control the appearance of the gradient. Used by 'MColorGradient',+'MFillGradient', and 'MStrokeGradient'.++@since 0.5.0.0++-}++data GradientProperty+  = GrX1 GradientCoord+    -- ^ The start of the color gradient (X axis); for radial+    --   gradients it represents the center of the inner circle.+    --+    --   The default for linear gradients is 0, and for radial+    --   gradients it is 0.5.+  | GrY1 GradientCoord+    -- ^ The start of the color gradient (Y axis); for radial+    --   gradients it represents the center of the inner circle.+    --+    --   The default for linear gradients is 0, and for radial+    --   gradients it is 0.5.+  | GrX2 GradientCoord+    -- ^ The end of the color gradient (X axis); for radial+    --   gradients it represents the center of the outer circle.+    --+    --   The default for linear gradients is 1, and for radial+    --   gradients it is 0.5.+  | GrY2 GradientCoord+    -- ^ The end of the color gradient (Y axis); for radial+    --   gradients it represents the center of the outer circle.+    --+    --   The default for linear gradients is 1, and for radial+    --   gradients it is 0.5.+  | GrR1 GradientCoord+    -- ^ The radius of the inner circle (radial color gradients+    --   only). The default is 0.+  | GrR2 GradientCoord+    -- ^ The radius of the outer circle (radial color gradients+    --   only). The default is 0.5.+++gradientProperty :: GradientProperty -> LabelledSpec+gradientProperty (GrX1 x) = "x1" .= x+gradientProperty (GrX2 x) = "x2" .= x+gradientProperty (GrY1 x) = "y1" .= x+gradientProperty (GrY2 x) = "y2" .= x+gradientProperty (GrR1 x) = "r1" .= x+gradientProperty (GrR2 x) = "r2" .= x+++{-|+Determine the direction to draw the text.++Used by 'MDir'.++@since 0.5.0.0+-}+data TextDirection+  = LTR+    -- ^ Left to right.+  | RTL+    -- ^ Right to left.++textdirLabel :: TextDirection -> T.Text+textdirLabel LTR = "ltr"+textdirLabel RTL = "rtl"
+ src/Graphics/Vega/VegaLite/Output.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Output+Copyright   : (c) Douglas Burke, 2018-2019+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings++Write out the VegaLite specification.++-}++module Graphics.Vega.VegaLite.Output+       ( toHtml+       , toHtmlFile+       , toHtmlWith+       , toHtmlFileWith+       ) where++import qualified Data.Aeson.Text as A+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.IO as TL++import Data.Aeson (Value)++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif++import Graphics.Vega.VegaLite.Specification (VegaLite, fromVL)+++{-|++Converts VegaLite to html Text. Uses Vega-Embed with the+default options. See 'toHtmlWith' for more control.++@since 0.2.1.0+-}+toHtml :: VegaLite -> TL.Text+toHtml = toHtmlWith Nothing++{-|++Converts VegaLite to an html file. Uses Vega-Embed with the+default options. See 'toHtmlFileWith' for more control.++@since 0.2.1.0+-}+toHtmlFile :: FilePath -> VegaLite -> IO ()+toHtmlFile file = TL.writeFile file . toHtml++{-|++Converts VegaLite to html Text. Uses Vega-Embed and is for when+some control is needed over the output: 'toHtml' is a simpler+form which just uses the default Vega-Embed options.++The render you use to view the output file must support Javascript,+since it is needed to create the visualization from the Vega-Lite+specification. The Vega and Vega-Lite Javascript versions are pegged+to 5 and 4, but no limit is applied to the Vega-Embed library.++@since 0.4.0.0+-}+toHtmlWith ::+  Maybe Value+  -- ^ The options to pass to the Vega-Embed @embed@ routine. See+  --   <https://github.com/vega/vega-embed#options> for the+  --   supported options.+  -> VegaLite+  -- ^ The Vega-Lite specification to display.+  -> TL.Text+toHtmlWith mopts vl =+  let spec = A.encodeToLazyText (fromVL vl)+      opts = maybe "" (\o -> "," <> A.encodeToLazyText o) mopts++  in TL.unlines+    [ "<!DOCTYPE html>"+    , "<html>"+    , "<head>"+      -- versions are fixed at vega 5, vega-lite 4+    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega@5\"></script>"+    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega-lite@4\"></script>"+    , "  <script src=\"https://cdn.jsdelivr.net/npm/vega-embed\"></script>"+    , "</head>"+    , "<body>"+    , "<div id=\"vis\"></div>"+    , "<script type=\"text/javascript\">"+    , "  var spec = " <> spec <> ";"+    , "  vegaEmbed(\'#vis\', spec" <> opts <> ").then(function(result) {"+    , "  // Access the Vega view instance (https://vega.github.io/vega/docs/api/view/) as result.view"+    , "  }).catch(console.error);"+    , "</script>"+    , "</body>"+    , "</html>"+    ]++{-|++Converts VegaLite to an html file. Uses Vega-Embed and is for when+some control is needed over the output: 'toHtmlFile' is a simpler+form which just uses the default Vega-Embed options.++@since 0.4.0.0+-}+toHtmlFileWith ::+  Maybe Value+  -- ^ The options to pass to the Vega-Embed @embed@ routine. See+  --   <https://github.com/vega/vega-embed#options> for the+  --   supported options.+  -> FilePath+  -- ^ The output file name (it will be over-written if it already exists).+  -> VegaLite+  -- ^ The Vega-Lite specification to display.+  -> IO ()+toHtmlFileWith mopts file = TL.writeFile file . toHtmlWith mopts+
+ src/Graphics/Vega/VegaLite/Scale.hs view
@@ -0,0 +1,141 @@+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Scale+Copyright   : (c) Douglas Burke, 2018-2019+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : OverloadedStrings++Scale-related functionality.++-}++module Graphics.Vega.VegaLite.Scale+       ( ScaleDomain(..)+       , ScaleRange(..)+       , ScaleNice(..)++         -- not for external export+       , scaleDomainSpec+       , scaleNiceSpec+       ) where++import qualified Data.Text as T++import Data.Aeson ((.=), object, toJSON)+++import Graphics.Vega.VegaLite.Foundation+  ( fromT+  )+import Graphics.Vega.VegaLite.Specification+  ( VLSpec+  )+import Graphics.Vega.VegaLite.Time+  ( DateTime+  , TimeUnit+  , dateTimeProperty+  , timeUnitLabel+  )+++{-|++Describes the scale domain (type of data in scale). For full details see the+<https://vega.github.io/vega-lite/docs/scale.html#domain Vega-Lite documentation>.+-}++data ScaleDomain+    = DNumbers [Double]+      -- ^ Numeric values that define a scale domain.+    | DStrings [T.Text]+      -- ^ String values that define a scale domain.+    | DDateTimes [[DateTime]]+      -- ^ Date-time values that define a scale domain.+    | DSelection T.Text+      -- ^ Scale domain based on a named interactive selection.+    | Unaggregated+    -- ^ Specify an unaggregated scale domain (type of data in scale).++scaleDomainSpec :: ScaleDomain -> VLSpec+scaleDomainSpec (DNumbers nums) = toJSON (map toJSON nums)+scaleDomainSpec (DDateTimes dts) = toJSON (map (object . map dateTimeProperty) dts)+scaleDomainSpec (DStrings cats) = toJSON (map toJSON cats)+scaleDomainSpec (DSelection selName) = object ["selection" .= selName]+scaleDomainSpec Unaggregated = "unaggregated"+++{-|++Describes the way a scale can be rounded to \"nice\" numbers. For full details see the+<https://vega.github.io/vega-lite/docs/scale.html#continuous Vega-Lite documentation>.+-}+data ScaleNice+    = NMillisecond+      -- ^ Nice time intervals that try to align with rounded milliseconds.+    | NSecond+      -- ^ Nice time intervals that try to align with whole or rounded seconds.+    | NMinute+      -- ^ Nice time intervals that try to align with whole or rounded minutes.+    | NHour+      -- ^ Nice time intervals that try to align with whole or rounded hours.+    | NDay+      -- ^ Nice time intervals that try to align with whole or rounded days.+    | NWeek+    -- ^ Nice time intervals that try to align with whole or rounded weeks.+    | NMonth+      -- ^ Nice time intervals that try to align with whole or rounded months.+    | NYear+      -- ^ Nice time intervals that try to align with whole or rounded years.+    | NInterval TimeUnit Int+      -- ^ \"Nice\" temporal interval values when scaling.+    | IsNice Bool+      -- ^ Enable or disable nice scaling.+    | NTickCount Int+      -- ^ Desired number of tick marks in a \"nice\" scaling.+++scaleNiceSpec :: ScaleNice -> VLSpec+scaleNiceSpec NMillisecond = fromT "millisecond"+scaleNiceSpec NSecond = fromT "second"+scaleNiceSpec NMinute = fromT "minute"+scaleNiceSpec NHour = fromT "hour"+scaleNiceSpec NDay = fromT "day"+scaleNiceSpec NWeek = fromT "week"+scaleNiceSpec NMonth = fromT "month"+scaleNiceSpec NYear = fromT "year"+scaleNiceSpec (NInterval tu step) =+  object ["interval" .= timeUnitLabel tu, "step" .= step]+scaleNiceSpec (IsNice b) = toJSON b+scaleNiceSpec (NTickCount n) = toJSON n+++{-|++Describes a scale range of scale output values. For full details see the+<https://vega.github.io/vega-lite/docs/scale.html#range Vega-Lite documentation>.++For color scales you can also specify a color [scheme](https://vega.github.io/vega-lite/docs/scale.html#scheme)+instead of range.++Any directly specified range for @x@ and @y@ channels will be ignored. Range can be customized+via the view's corresponding [size](https://vega.github.io/vega-lite/docs/size.html)+('Graphics.Vega.VegaLite.width' and 'Graphics.Vega.VegaLite.height') or via range steps and paddings properties (e.g. 'Graphics.Vega.VegaLite.SCRangeStep')+for band and point scales.++-}++data ScaleRange+    = RNumbers [Double]+      -- ^ For [continuous scales](https://vega.github.io/vega-lite/docs/scale.html#continuous),+      --   a two-element array indicating minimum and maximum values, or an array with more than+      --   two entries for specifying a+      --   [piecewise scale](https://vega.github.io/vega-lite/docs/scale.html#piecewise).+    | RStrings [T.Text]+      -- ^ Text scale range for discrete scales.+    | RName T.Text+      -- ^ Name of a [pre-defined named scale range](https://vega.github.io/vega-lite/docs/scale.html#range-config)+      --   (e.g. \"symbol\" or \"diverging\").
+ src/Graphics/Vega/VegaLite/Selection.hs view
@@ -0,0 +1,530 @@+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Selection+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : OverloadedStrings++User selections.++-}++module Graphics.Vega.VegaLite.Selection+       ( selection+       , select+       , Selection(..)+       , SelectionProperty(..)+       , Binding(..)+       , BindLegendProperty(..)+       , InputProperty(..)+       , SelectionMarkProperty(..)+       , SelectionResolution(..)++       -- not for external export+       , selectionProperties+       , selectionLabel+       )+    where++import qualified Data.Text as T++import Control.Arrow (second)++import Data.Aeson ((.=), object, toJSON)+import Data.Maybe (mapMaybe)+++import Graphics.Vega.VegaLite.Data+  ( DataValue+  , dataValueSpec+  )+import Graphics.Vega.VegaLite.Foundation+  ( Color+  , DashStyle+  , DashOffset+  , FieldName+  , Opacity+  , Channel+  , channelLabel+  , fromT+  , fromColor+  , fromDS+  )+import Graphics.Vega.VegaLite.Specification+  ( VLProperty(VLSelection)+  , PropertySpec+  , LabelledSpec+  , SelectSpec(..)+  , BuildSelectSpecs+  , SelectionLabel+  )+++-- | Indicates the type of selection to be generated by the user.++data Selection+    = Single+      -- ^ Allows one mark at a time to be selected.+    | Multi+      -- ^ Allows multiple items to be selected (e.g. with+      --   shift-click).+    | Interval+      -- ^ Allows a bounding rectangle to be dragged by the user,+      --   selecting all items which intersect it.+++selectionLabel :: Selection -> T.Text+selectionLabel Single = "single"+selectionLabel Multi = "multi"+selectionLabel Interval = "interval"+++{-|++Properties for customising the nature of the selection. See the+<https://vega.github.io/vega-lite/docs/selection.html#selection-properties Vega-Lite documentation>+for details.++For use with 'select' and 'Graphics.Vega.VegaLite.SelectionStyle'.+-}+data SelectionProperty+    = Empty+      -- ^ Make a selection empty by default when nothing selected.+    | BindScales+      -- ^ Enable two-way binding between a selection and the scales used+      --   in the same view. This is commonly used for zooming and panning+      --   by binding selection to position scaling:+      --+      --   @sel = 'selection' . 'select' \"mySelection\" 'Interval' ['BindScales']@+    | BindLegend BindLegendProperty+      -- ^ Enable binding between a legend selection and the item it+      --   references. This is __only applicable__ to categorical (symbol)+      --   legends.+      --+      --   The following will allow the \"crimeType\" legend to be selected:+      --+      --   @+      --   'select' \"mySelection\" 'Single' [ 'BindLegend' ('BLField' \"crimeType\") ]+      --   @+      --+      --   Use 'On' to make a two-way binding (that is, selecting the legend or the symbol+      --   type will highlight the other):+      --+      --   @+      --   'select' \"sel\" 'Multi' [ 'On' \"click\"+      --                      , 'BindLegend' ('BLFieldEvent' \"crimeType\" \"dblclick\")+      --                      ]+      --   @+      --+      --   @since 0.5.0.0+    | On T.Text+      -- ^ [Vega event stream selector](https://vega.github.io/vega/docs/event-streams/#selector)+      --   that triggers a selection, or the empty string (which sets the property to @false@).+    | Clear T.Text+      -- ^ [Vega event stream selector](https://vega.github.io/vega/docs/event-streams/#selector)+      --   that can clear a selection. For example, to allow a zoomed/panned view to be reset+      --   on shift-click:+      --+      -- @+      -- 'selection'+      --     . 'select' \"myZoomPan\"+      --         'Interval'+      --         ['BindScales', 'Clear' \"click[event.shiftKey]\"]+      -- @+      --+      --   To remove the default clearing behaviour of a selection, provide an empty string+      --   rather than an event stream selector.+      --+      --   @since 0.4.0.0+    | Translate T.Text+      -- ^ Translation selection transformation used for panning a view. See the+      --   [Vega-Lite translate documentation](https://vega.github.io/vega-lite/docs/translate.html).+    | Zoom T.Text+      -- ^ Zooming selection transformation used for zooming a view. See the+      --   [Vega-Lite zoom documentation](https://vega.github.io/vega-lite/docs/zoom.html).+    | Fields [FieldName]+      -- ^ Field names for projecting a selection.+    | Encodings [Channel]+      -- ^ Encoding channels that form a named selection.+      --+      --   For example, to __project__ a selection across all items that+      --   share the same value in the color channel:+      --+      --   @sel = 'selection' . 'select' \"mySelection\" 'Multi' ['Encodings' ['Graphics.Vega.VegaLite.ChColor']]@+    | SInit [(FieldName, DataValue)]+      -- ^ Initialise one or more selections with values from bound fields.+      --   See also 'SInitInterval'.+      --+      --   For example,+      --+      --   @+      --   'selection'+      --       . 'select' \"CylYr\"+      --           'Single'+      --           [ 'Fields' [\"Cylinders\", \"Year\"]+      --           , 'SInit'+      --               [ (\"Cylinders\", 'Graphics.Vega.VegaLite.Number' 4)+      --               , (\"Year\", 'Graphics.Vega.VegaLite.Number' 1977)+      --               ]+      --           , 'Bind'+      --               [ 'IRange' \"Cylinders\" ['InMin' 3, 'InMax' 8, 'InStep' 1]+      --               , 'IRange' \"Year\" ['InMin' 1969, 'InMax' 1981, 'InStep' 1]+      --               ]+      --           ]+      --   @+      --+      --   @since 0.4.0.0+    | SInitInterval (Maybe (DataValue, DataValue)) (Maybe (DataValue, DataValue))+      -- ^ Initialize the domain extent of an interval selection. See+      --   also 'SInit'.+      --+      --   The parameters refer to the x and y axes, given in the order+      --   @(minimum, maximum)@ for each axis. If an axis is set to+      --   @Nothing@ then the selection is projected over that+      --   dimension. At least one of the two arguments should be+      --   set (i.e. not @Nothing@).+      --+      --   @+      --   'select' \"mySelection\"+      --          'Interval'+      --          [ 'SInitInterval'+      --              (Just ( 'Graphics.Vega.VegaLite.DateTime' ['Graphics.Vega.VegaLite.DTYear' 2013]+      --                    , 'Graphics.Vega.VegaLite.DateTime' ['Graphics.Vega.VegaLite.DTYear' 2015]+      --                    )+      --              (Just ('Graphics.Vega.VegaLite.Number' 40, 'Graphics.Vega.VegaLite.Number' 80))+      --          ]+      --   @+      --+      --   @since 0.4.0.0+    | ResolveSelections SelectionResolution+      -- ^ Strategy that determines how selections' data queries are resolved when applied+      --   in a filter transform, conditional encoding rule, or scale domain.+    | SelectionMark [SelectionMarkProperty]+      -- ^ Appearance of an interval selection mark (dragged rectangle).+    | Bind [Binding]+      -- ^ Binding to some input elements as part of a named selection.+      --+      --   The followig example allows a selection to be based on a+      --   drop-down list of options:+      --+      --   @+      --   sel = 'selection'+      --           . 'select' \"mySelection\"+      --               'Single'+      --               ['Fields' [\"crimeType\"]+      --               , 'Bind' ['ISelect' \"crimeType\"+      --                         ['InOptions'+      --                            [ \"Anti-social behaviour\"+      --                            , \"Criminal damage and arson\"+      --                            , \"Drugs\"+      --                            , \"Robbery\"+      --                            , \"Vehicle crime\"+      --                            ]+      --                         ]+      --                      ]+      --               ]+      --   @+    | Nearest Bool+      -- ^ Whether or not a selection should capture nearest marks to a pointer+      --   rather than an exact position match.+    | Toggle T.Text+      -- ^ Predicate expression that determines a toggled selection. See the+      --   [Vega-Lite toggle documentation](https://vega.github.io/vega-lite/docs/toggle.html).+++selectionProperties :: SelectionProperty -> [LabelledSpec]+selectionProperties (Fields fNames) = ["fields" .= fNames]+selectionProperties (Encodings channels) = ["encodings" .= map channelLabel channels]+selectionProperties (SInit iVals) = ["init" .= object (map (second dataValueSpec) iVals)]+selectionProperties (SInitInterval Nothing Nothing) = []+selectionProperties (SInitInterval mx my) =+  let conv (_, Nothing) = Nothing+      conv (lbl, Just (lo, hi)) = Just (lbl .= [ dataValueSpec lo, dataValueSpec hi ])++  in ["init" .= object (mapMaybe conv (zip ["x", "y"] [mx, my]))]++selectionProperties (On e) = ["on" .= e]+selectionProperties (Clear e) =+  let t = T.strip e+  in ["clear" .= if T.null t then toJSON False else toJSON t]++selectionProperties Empty = ["empty" .= fromT "none"]+selectionProperties (ResolveSelections res) = ["resolve" .= selectionResolutionLabel res]+selectionProperties (SelectionMark markProps) = ["mark" .= object (map selectionMarkProperty markProps)]+selectionProperties BindScales = ["bind" .= fromT "scales"]+selectionProperties (BindLegend blp) = bindLegendProperty blp+selectionProperties (Bind binds) = ["bind" .= object (map bindingSpec binds)]+selectionProperties (Nearest b) = ["nearest" .= b]+selectionProperties (Toggle expr) = ["toggle" .= expr]+selectionProperties (Translate e) = ["translate" .= if T.null e then toJSON False else toJSON e]+selectionProperties (Zoom e) = ["zoom" .= if T.null e then toJSON False else toJSON e]+++{-|++Determines how selections in faceted or repeated views are resolved. See the+<https://vega.github.io/vega-lite/docs/selection.html#resolve Vega-Lite documentation>+for details.++For use with 'ResolveSelections'.++-}+data SelectionResolution+    = Global+      -- ^ One selection available across all subviews (default).+    | Union+      -- ^ Each subview contains its own brush and marks are selected if they lie+      --   within /any/ of these individual selections.+    | Intersection+      -- ^  Each subview contains its own brush and marks are selected if they lie+      --    within /all/ of these individual selections.+++selectionResolutionLabel :: SelectionResolution -> T.Text+selectionResolutionLabel Global = "global"+selectionResolutionLabel Union = "union"+selectionResolutionLabel Intersection = "intersect"+++{-|++Properties for customising the appearance of an interval selection+mark (a dragged rectangle). For details see the+<https://vega.github.io/vega-lite/docs/selection.html#interval-mark Vega-Lite documentation>.++-}+data SelectionMarkProperty+    = SMFill Color+      -- ^ Fill color.+    | SMFillOpacity Opacity+      -- ^ Fill opacity.+    | SMStroke Color+      -- ^ The stroke color.+    | SMStrokeOpacity Opacity+      -- ^ The stroke opacity.+    | SMStrokeWidth Double+      -- ^ The line width of the stroke.+    | SMStrokeDash DashStyle+      -- ^ The dash pattern for the stroke.+    | SMStrokeDashOffset DashOffset+      -- ^ The offset at which to start the dash pattern.+++selectionMarkProperty :: SelectionMarkProperty -> LabelledSpec+selectionMarkProperty (SMFill colour) = "fill" .= fromColor colour+selectionMarkProperty (SMFillOpacity x) = "fillOpacity" .= x+selectionMarkProperty (SMStroke colour) = "stroke" .= fromColor colour+selectionMarkProperty (SMStrokeOpacity x) = "strokeOpacity" .= x+selectionMarkProperty (SMStrokeWidth x) = "strokeWidth" .= x+selectionMarkProperty (SMStrokeDash xs) = "strokeDash" .= fromDS xs+selectionMarkProperty (SMStrokeDashOffset x) = "strokeDashOffset" .= x+++{-|++GUI Input properties. The type of relevant property will depend on the type of+input element selected. For example an @InRange@ (slider) can have numeric min,+max and step values; @InSelect@ (selector) has a list of selection label options.+For details see the+<https://vega.github.io/vega/docs/signals/#bind Vega input element binding documentation>.++-}++-- based on schema 3.3.0 #/definitions/BindRange+--       or              #/definitions/InputBinding++-- placeholder is in InputBinding+-- debounce is in BindCheckbox / BindRadioSelect / BindRange / InputBinding+-- element is in BindCheckbox / BindRadioSelect / BindRange / InputBinding++-- but InputBinding doesn't have min/max/others++data InputProperty+    = Debounce Double+      -- ^ The delay to introduce when processing input events to avoid+      --   unnescessary event broadcasting.+    | Element T.Text+      -- ^ CSS selector indicating the parent element to which an input+      --   element should be added. This allows for interacting with+      --   elements outside the visualization container.+    | InOptions [T.Text]+      -- ^ The options for a radio or select input element.+    | InMin Double+      -- ^ The minimum slider value for a range input element.+    | InMax Double+      -- ^ The maximum slider value for a range input element.+    | InName T.Text+      -- ^ Custom label for a radio or select input element.+    | InStep Double+      -- ^ The minimum increment for a range sliders.+    | InPlaceholder T.Text+      -- ^ The initial text for input elements such as text fields.+++inputProperty :: InputProperty -> LabelledSpec+inputProperty (Debounce x) = "debounce" .= x+inputProperty (Element el) = "element" .= el -- #/definitions/Element+inputProperty (InOptions opts) = "options" .= map toJSON opts+inputProperty (InMin x) = "min" .= x+inputProperty (InMax x) = "max" .= x+inputProperty (InName s) = "name" .= s+inputProperty (InStep x) = "step" .= x+inputProperty (InPlaceholder el) = "placeholder" .= toJSON el+++{-|++Describes the binding property of a selection based on some HTML input element+such as a checkbox or radio button. For details see the+<https://vega.github.io/vega-lite/docs/bind.html#scale-binding Vega-Lite documentation>+and the+<https://vega.github.io/vega/docs/signals/#bind Vega input binding documentation>.+-}+data Binding+    = IRange T.Text [InputProperty]+      -- ^ Range slider input element that can bound to a named field value.+    | ICheckbox T.Text [InputProperty]+      -- ^ Checkbox input element that can bound to a named field value.+    | IRadio T.Text [InputProperty]+      -- ^ Radio box input element that can bound to a named field value.+    | ISelect T.Text [InputProperty]+      -- ^ Select input element that can bound to a named field value.+    | IText T.Text [InputProperty]+      -- ^ Text input element that can bound to a named field value.+    | INumber T.Text [InputProperty]+      -- ^ Number input element that can bound to a named field value.+    | IDate T.Text [InputProperty]+      -- ^ Date input element that can bound to a named field value.+    | ITime T.Text [InputProperty]+      -- ^ Time input element that can bound to a named field value.+    | IMonth T.Text [InputProperty]+      -- ^ Month input element that can bound to a named field value.+    | IWeek T.Text [InputProperty]+      -- ^ Week input element that can bound to a named field value.+    | IDateTimeLocal T.Text [InputProperty]+      -- ^ Local time input element that can bound to a named field value.+    | ITel T.Text [InputProperty]+      -- ^ Telephone number input element that can bound to a named field value.+    | IColor T.Text [InputProperty]+      -- ^ Color input element that can bound to a named field value.+++bindingSpec :: Binding -> LabelledSpec+bindingSpec bnd =+  let (lbl, input, ps) = case bnd of+        IRange label props -> (label, fromT "range", props)+        ICheckbox label props -> (label, "checkbox", props)+        IRadio label props -> (label, "radio", props)+        ISelect label props -> (label, "select", props)+        IText label props -> (label, "text", props)+        INumber label props -> (label, "number", props)+        IDate label props -> (label, "date", props)+        ITime label props -> (label, "time", props)+        IMonth label props -> (label, "month", props)+        IWeek label props -> (label, "week", props)+        IDateTimeLocal label props -> (label, "datetimelocal", props)+        ITel label props -> (label, "tel", props)+        IColor label props -> (label, "color", props)++  in (lbl, object (("input" .= input) : map inputProperty ps))+++{-|++Control the interactivity of the legend. This is used with 'BindLegend'.++@since 0.5.0.0++-}+data BindLegendProperty+  = BLField FieldName+    -- ^ The data field which should be made interactive in the legend+    --   on a single click.+  | BLChannel Channel+    -- ^ Which channel should be made interactive in a legend+    --   on a single click.+  | BLFieldEvent FieldName T.Text+    -- ^ The data field which should be made interactive in the legend and the+    --   <https://vega.github.io/vega/docs/event-streams Vega event stream>+    --   that should trigger the selection.+  | BLChannelEvent Channel T.Text+    -- ^ Which channel should be made interactive in a legend and the+    --   <https://vega.github.io/vega/docs/event-streams Vega event stream>+    --   that should trigger the selection.+++bindLegendProperty :: BindLegendProperty -> [LabelledSpec]+bindLegendProperty (BLField f) = [ toLBind Nothing+                                 , "fields" .= [f]+                                 ]+bindLegendProperty (BLChannel ch) = [ toLBind Nothing+                                    , "encodings" .= [channelLabel ch]+                                    ]+bindLegendProperty (BLFieldEvent f es) = [ toLBind (Just es)+                                         , "fields" .= [f]+                                         ]+bindLegendProperty (BLChannelEvent ch es) = [ toLBind (Just es)+                                            , "encodings" .= [channelLabel ch]+                                            ]++toLBind :: Maybe T.Text -> LabelledSpec+toLBind Nothing = "bind" .= fromT "legend"+toLBind (Just es) = "bind" .= object ["legend" .= es]+++{-|++Create a full selection specification from a list of selections. For details+see the+<https://vega.github.io/vega-lite/docs/selection.html Vega-Lite documentation>.++@+sel =+   'selection'+       . 'select' \"view\" 'Interval' ['BindScales'] []+       . 'select' \"myBrush\" 'Interval' []+       . 'select' \"myPaintbrush\" 'Multi' ['On' \"mouseover\", 'Nearest' True]+@++-}++selection ::+  [SelectSpec]+  -- ^ The arguments created by 'Graphics.Vega.VegaLite.select'.+  --+  --   Prior to @0.5.0.0@ this argument was @['LabelledSpec']@.+  -> PropertySpec+selection sels = (VLSelection, object (map unS sels))+++{-|++Create a single named selection that may be applied to a data query or+transformation.++@+sel =+    'selection'+        . 'select' "view" 'Interval' [ 'BindScales' ] []+        . 'select' "myBrush" 'Interval' []+        . 'select' "myPaintbrush" 'Multi' [ 'On' "mouseover", 'Nearest' True ]+@++-}+select ::+  SelectionLabel+  -- ^ The name given to the selection.+  -> Selection+  -- ^ The type of the selection.+  -> [SelectionProperty]+  -- ^ What options are applied to the selection.+  -> BuildSelectSpecs+  -- ^ Prior to @0.5.0.0@ this was @BuildLabelledSpecs@.+select nme sType options ols =+  -- TODO: elm filters out those properties that are set to A.Null+  let selProps = ("type" .= selectionLabel sType) : concatMap selectionProperties options+  in S (nme .= object selProps) : ols
+ src/Graphics/Vega/VegaLite/Specification.hs view
@@ -0,0 +1,843 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Specification+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings++The structure of the Vega-Lite specification.++-}++module Graphics.Vega.VegaLite.Specification+       ( toVegaLite+       , toVegaLiteSchema+       , vlSchema2, vlSchema3, vlSchema4, vlSchema+       , fromVL+       , VLProperty(..)+       , VLSpec+       , VegaLite+       , PropertySpec+       , LabelledSpec+       , EncodingSpec(..)+       , toEncodingSpec+       , fromEncodingSpec+       , BuildEncodingSpecs+       , TransformSpec(..)+       , toTransformSpec+       , fromTransformSpec+       , BuildTransformSpecs+       , ResolveSpec(..)+       , toResolveSpec+       , fromResolveSpec+       , BuildResolveSpecs+       , SelectSpec(..)+       , toSelectSpec+       , fromSelectSpec+       , BuildSelectSpecs+       , ConfigureSpec(..)+       , toConfigureSpec+       , fromConfigureSpec+       , BuildConfigureSpecs+       , asSpec+       , specification+       , SelectionLabel+       )+    where++-- VegaLite uses these symbols.+import Prelude hiding (filter, lookup, repeat)++import qualified Data.Text as T++import Control.Arrow (first)++-- Aeson's Value type conflicts with the Number type+import Data.Aeson (Value, object, (.=))+import Data.Maybe (catMaybes, fromMaybe)++#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)+++-- | A Vega Lite visualization, created by+--   'toVegaLite'. The contents can be extracted with 'fromVL'.+--+newtype VegaLite = VL (T.Text, [LabelledSpec])+++-- | The Vega-Lite specification is represented as JSON.+type VLSpec = Value++baseSchema :: T.Text+baseSchema = "https://vega.github.io/schema/vega-lite/"++-- | The latest version 2 Vega-Lite schema (equivalent to+--   @'vlSchema' 2 Nothing Nothing Nothing@).+vlSchema2 :: T.Text+vlSchema2 = vlSchema 2 Nothing Nothing Nothing++-- | The latest version 3 Vega-Lite schema (equivalent to+--   @'vlSchema' 3 Nothing Nothing Nothing@).+vlSchema3 :: T.Text+vlSchema3 = vlSchema 3 Nothing Nothing Nothing++-- | The latest version 4 Vega-Lite schema (equivalent to+--   @'vlSchema' 4 Nothing Nothing Nothing@).+vlSchema4 :: T.Text+vlSchema4 = vlSchema 4 Nothing Nothing Nothing++-- | Create the Vega-Lite schema for an arbitrary version. See+--   <https://github.com/vega/schema> for more information on naming+--   and availability.+--+--   There is no validation of the input values.+--+--   Alpha and Beta releases can be specified by setting+--   the last argument; for instance to get the \"beta.0\"+--   version of version 4 you would use+--+--   @vlSchema 4 (Just 0) (Just 0) (Just "-beta.0")@+--+--   whereas+--+--   @vlSchema 4 Nothing Nothing Nothing@+--+--   refers to the latest release of version 4.+--+vlSchema ::+  Natural+  -- ^ The major version+  -> Maybe Natural+  -- ^ The minor version+  -> Maybe Natural+  -- ^ The \"micro\" version+  -> Maybe T.Text+  -- ^ Anything beyond "major.minor.micro" (e.g. \"-beta.0").+  -> T.Text+  -- ^ The Vega-Lite Schema+vlSchema major mminor mmicro mextra =+  let versions = [ pure (showNat major)+                 , showNat <$> mminor+                 , showNat <$> mmicro+                 ]+      version = T.intercalate "." (catMaybes versions)++  in baseSchema <> "v" <> version <> fromMaybe "" mextra <> ".json"+++showNat :: Natural -> T.Text+showNat = T.pack . show+++{-|++Convert a list of Vega-Lite specifications into a single JSON object+that may be passed to Vega-Lite for graphics generation. Commonly+these will include at least a data, mark, and encoding specification.++While simple properties like 'Graphics.Vega.VegaLite.mark' may be provided directly, it is+usually clearer to label more complex ones such as encodings as+separate expressions. This becomes increasingly helpful for+visualizations that involve composition of layers, repeats and facets.++Specifications can be built up by chaining a series of functions (such+as 'Graphics.Vega.VegaLite.dataColumn' or 'Graphics.Vega.VegaLite.position' in the example below). Functional+composition using the '.' operator allows this to be done compactly.++@+let dat = 'Graphics.Vega.VegaLite.dataFromColumns' []+          . 'Graphics.Vega.VegaLite.dataColumn' "a" ('Graphics.Vega.VegaLite.Strings' [ \"C", \"C", \"D", \"D", \"E", \"E" ])+          . 'Graphics.Vega.VegaLite.dataColumn' "b" ('Graphics.Vega.VegaLite.Numbers' [ 2, 7, 1, 2, 6, 8 ])++    enc = 'Graphics.Vega.VegaLite.encoding'+          . 'Graphics.Vega.VegaLite.position' 'Graphics.Vega.VegaLite.X' [ 'Graphics.Vega.VegaLite.PName' "a", 'Graphics.Vega.VegaLite.PmType' 'Graphics.Vega.VegaLite.Nominal' ]+          . 'Graphics.Vega.VegaLite.position' 'Graphics.Vega.VegaLite.Y' [ 'Graphics.Vega.VegaLite.PName' "b", 'Graphics.Vega.VegaLite.PmType' 'Graphics.Vega.VegaLite.Quantitative', 'Graphics.Vega.VegaLite.PAggregate' 'Graphics.Vega.VegaLite.Mean' ]++in 'toVegaLite' [ dat [], 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Bar' [], enc [] ]+@++The schema used is <https://github.com/vega/schema version 4 of Vega-Lite>,+and please [report an issue](https://github.com/DougBurke/hvega/issues) if+you find a problem with the output of @hvega@. Use 'toVegaLiteSchema' if you+need to create a Vega-Lite specification which uses a different version of+the schema.++-}++toVegaLite :: [PropertySpec] -> VegaLite+toVegaLite = toVegaLiteSchema vlSchema4+++{-|+A version of 'toVegaLite' that allows you to change the Vega-Lite+schema version of the visualization.++@+'toVegaLiteSchema' 'vlSchema3' props+@++Note that the schema is __only used__ to fill in the @\"$schema\"@+field of the JSON structure. It __does not__ change the JSON+encoding of the visualization.++-}++toVegaLiteSchema ::+  T.Text+  -- ^ The schema to use (e.g. 'vlSchema4' or created with 'vlSchema').+  --+  --   There is __no check__ that this schema represents Vega-Lite,+  --   and is just treated as a value added to the output JSON.+  --+  -> [PropertySpec]+  -- ^ The visualization.+  -> VegaLite+toVegaLiteSchema schema props = VL (schema, unProperty props)+++unProperty :: [PropertySpec] -> [LabelledSpec]+unProperty = map (first vlPropertyLabel)+++{-|++Obtain the Vega-Lite JSON (i.e. specification) for passing to a+Vega-Lite visualizer.++> let vlSpec = fromVL vl+> Data.ByteString.Lazy.Char8.putStrLn (Data.Aeson.Encode.Pretty.encodePretty vlSpec)++Note that there is __no__ validation done to ensure that the+output matches the Vega Lite schema. That is, it is possible to+create an invalid visualization with this module (e.g. missing a+data source or referring to an undefined field).++-}++fromVL ::+  VegaLite+  -> Value+  -- ^ Prior to version @0.5.0.0@ this was labelled as returning a 'VLSpec'+  --   value. It has been changed to 'Value' to indicate that this is the+  --   JSON representation of the visualization (noting that @VLSpec@ is+  --   an alias for @Value@).+fromVL (VL (schema, specs)) =+  let kvals = ("$schema" .= schema) : specs+  in object kvals+++{-|++Create a specification sufficient to define an element in a composed visualization+such as a superposed layer or juxtaposed facet. Typically a layer will contain a+full set of specifications that define a visualization with+the exception of the data specification which is usually defined outside of any one+layer. Whereas for repeated and faceted specs, the entire specification is provided.++@+spec1 = asSpec [ enc1 [], 'Graphics.Vega.VegaLite.mark' 'Graphics.Vega.VegaLite.Line' [] ]+@+-}+asSpec :: [PropertySpec] -> VLSpec+asSpec = object . unProperty+++{-|++Defines a specification object for use with faceted and repeated small multiples.++@+'toVegaLite'+    [ 'Graphics.Vega.VegaLite.facet' [ 'Graphics.Vega.VegaLite.RowBy' [ 'Graphics.Vega.VegaLite.FName' \"Origin\", 'Graphics.Vega.VegaLite.FmType' 'Graphics.Vega.VegaLite.Nominal' ] ]+    , 'specification' spec+    ]+@+-}+specification :: VLSpec -> PropertySpec+specification spec = (VLSpecification, spec)+++{-|++A convenience type-annotation label. It is the same as 'Graphics.Vega.VegaLite.Data'.++@since 0.4.0.0+-}+type PropertySpec = (VLProperty, VLSpec)++{-|++Represents a named Vega-Lite specification, usually generated by a+function in this module. You shouldn't need to create @LabelledSpec@+tuples directly, but they can be useful for type annotations.+-}+type LabelledSpec = (T.Text, VLSpec)++{-|++Represent an encoding (input to 'Graphics.Vega.VegaLite.encoding').++It is expected that routines like 'Graphics.Vega.VegaLite.position'+and 'Graphics.Vega.VegaLite.color' are used to create values with this+type, but they can also be constructed and deconstructed manually+with 'toEncodingSpec' and 'fromEncodingSpec'.++@since 0.5.0.0++-}++newtype EncodingSpec = ES { unES :: (T.Text, VLSpec) }+++{-|++This function is provided in case there is any need to inject+JSON into the Vega-Lite document that @hvega@ does not support+(due to changes in the Vega-Lite specification or missing+functionality in this module). If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'fromEncodingSpec'.++@since 0.5.0.0+-}++toEncodingSpec ::+  T.Text+  -- ^ The key to use for these settings (e.g. @\"color\"@ or @\"position\"@).+  -> VLSpec+  -- ^ The value of the key. This is expected to be an object, but there+  --   is no check on the value.+  --+  --   See the <https://github.com/vega/schema/tree/master/vega-lite Vega-Lite schema>+  --   for information on the supported values.+  -> EncodingSpec+toEncodingSpec lbl spec = ES (lbl, spec)+++{-|++Extract the contents of an encoding specification. This may be+needed when the Vega-Lite specification adds or modifies settings+for a particular encoding, and @hvega@ has not been updated+to reflect this change. If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'toEncodingSpec'.++@since 0.5.0.0+-}++fromEncodingSpec ::+  EncodingSpec+  -> (T.Text, VLSpec)+  -- ^ The key for the settings (e.g. \"detail\") and the value of the+  --   key.+fromEncodingSpec = unES+++{-|+Represent the functions that can be chained together and sent to+'Graphics.Vega.VegaLite.encoding'.++@since 0.5.0.0+-}++type BuildEncodingSpecs = [EncodingSpec] -> [EncodingSpec]++{-|++Represent a transformation (input to 'Graphics.Vega.VegaLite.transform').++It is expected that routines like 'Graphics.Vega.VegaLite.calculateAs'+and 'Graphics.Vega.VegaLite.filter' are used to create values with this+type, but they can also be constructed and deconstructed manually+with 'toTransformSpec' and 'fromTransformSpec'.++@since 0.5.0.0++-}++newtype TransformSpec = TS { unTS :: VLSpec }++{-|++This function is provided in case there is any need to inject+JSON into the Vega-Lite document that @hvega@ does not support+(due to changes in the Vega-Lite specification or missing+functionality in this module). If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'fromTransformSpec'.++@since 0.5.0.0+-}++toTransformSpec ::+  VLSpec+  -- ^ The tranform value, which is expected to be an object, but there+  --   is no check on this.+  --+  --   See the <https://github.com/vega/schema/tree/master/vega-lite Vega-Lite schema>+  --   for information on the supported values.+  -> TransformSpec+toTransformSpec = TS+++{-|++Extract the contents of a transformation specification. This may be+needed when the Vega-Lite specification adds or modifies settings+for a particular encoding, and @hvega@ has not been updated+to reflect this change. If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'toTransformSpec'.++@since 0.5.0.0+-}++fromTransformSpec ::+  TransformSpec+  -> VLSpec+  -- ^ The transformation data.+fromTransformSpec = unTS++{-|+Represent the functions that can be chained together and sent to+'Graphics.Vega.VegaLite.transform'.++@since 0.5.0.0+-}++type BuildTransformSpecs = [TransformSpec] -> [TransformSpec]+++{-|++Represent a set of resolution properties+(input to 'Graphics.Vega.VegaLite.resolve').++It is expected that 'Graphics.Vega.VegaLite.resolution' is used+to create values with this type, but they can also be constructed and+deconstructed manually with 'toResolveSpec' and 'fromResolveSpec'.++@since 0.5.0.0++-}++newtype ResolveSpec = RS { unRS :: (T.Text, VLSpec) }+++{-|++This function is provided in case there is any need to inject+JSON into the Vega-Lite document that @hvega@ does not support+(due to changes in the Vega-Lite specification or missing+functionality in this module). If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'fromResolveSpec'.++@since 0.5.0.0+-}++toResolveSpec ::+  T.Text+  -- ^ The key to use for these settings (e.g. @\"axis\"@ or @\"scale\"@).+  -> VLSpec+  -- ^ The value of the key. This is expected to be an object, but there+  --   is no check on the value.+  --+  --   See the <https://github.com/vega/schema/tree/master/vega-lite Vega-Lite schema>+  --   for information on the supported values.+  -> ResolveSpec+toResolveSpec lbl spec = RS (lbl, spec)+++{-|++Extract the contents of an resolve specification. This may be+needed when the Vega-Lite specification adds or modifies settings+for a particular resolve, and @hvega@ has not been updated+to reflect this change. If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'toResolveSpec'.++@since 0.5.0.0+-}++fromResolveSpec ::+  ResolveSpec+  -> (T.Text, VLSpec)+  -- ^ The key for the settings (e.g. \"legend\") and the value of the+  --   key.+fromResolveSpec = unRS+++{-|+Represent the functions that can be chained together and sent to+'Graphics.Vega.VegaLite.resolve'.++@since 0.5.0.0+-}++type BuildResolveSpecs = [ResolveSpec] -> [ResolveSpec]+++{-|++Represent a set of resolution properties+(input to 'Graphics.Vega.VegaLite.selection').++It is expected that 'Graphics.Vega.VegaLite.select' is used+to create values with this type, but they can also be constructed and+deconstructed manually with 'toSelectSpec' and 'fromSelectSpec'.++@since 0.5.0.0++-}++newtype SelectSpec = S { unS :: (T.Text, VLSpec) }+++{-|++This function is provided in case there is any need to inject+JSON into the Vega-Lite document that @hvega@ does not support+(due to changes in the Vega-Lite specification or missing+functionality in this module). If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'fromSelectSpec'.++@since 0.5.0.0+-}++toSelectSpec ::+  SelectionLabel+  -- ^ The name given to the selection.+  -> VLSpec+  -- ^ The value of the key. This is expected to be an object, but there+  --   is no check on the value.+  --+  --   See the <https://github.com/vega/schema/tree/master/vega-lite Vega-Lite schema>+  --   for information on the supported values.+  -> SelectSpec+toSelectSpec lbl spec = S (lbl, spec)+++{-|++Extract the contents of a select specification. This may be+needed when the Vega-Lite specification adds or modifies settings+for a particular select, and @hvega@ has not been updated+to reflect this change. If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'toSelectSpec'.++@since 0.5.0.0+-}++fromSelectSpec ::+  SelectSpec+  -> (SelectionLabel, VLSpec)+  -- ^ The name for the selection and its settings.+fromSelectSpec = unS+++{-|+Represent the functions that can be chained together and sent to+'Graphics.Vega.VegaLite.selection'.++@since 0.5.0.0+-}++type BuildSelectSpecs = [SelectSpec] -> [SelectSpec]+++{-|++Represent a set of configuration properties+(input to 'Graphics.Vega.VegaLite.configuration').++It is expected that 'Graphics.Vega.VegaLite.configuration' is used+to create values with this type, but they can also be constructed and+deconstructed manually with 'toConfigureSpec' and 'fromConfigureSpec'.++@since 0.5.0.0++-}++newtype ConfigureSpec = CS { unCS :: (T.Text, VLSpec) }+++{-|++This function is provided in case there is any need to inject+JSON into the Vega-Lite document that @hvega@ does not support+(due to changes in the Vega-Lite specification or missing+functionality in this module). If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'fromConfigureSpec'.++@since 0.5.0.0+-}++toConfigureSpec ::+  T.Text+  -- ^ The key to use for these settings (e.g. @\"axis\"@ or @\"background\"@).+  -> VLSpec+  -- ^ The value of the key.+  --+  --   See the <https://github.com/vega/schema/tree/master/vega-lite Vega-Lite schema>+  --   for information on the supported values.+  -> ConfigureSpec+toConfigureSpec lbl spec = CS (lbl, spec)+++{-|++Extract the contents of a configuration specification. This may be+needed when the Vega-Lite specification adds or modifies settings+for a particular configure, and @hvega@ has not been updated+to reflect this change. If you find yourself needing+to use this then please+<https://github.com/DougBurke/hvega/issues report an issue>.++See also 'toConfigureSpec'.++@since 0.5.0.0+-}++fromConfigureSpec ::+  ConfigureSpec+  -> (T.Text, VLSpec)+  -- ^ The key for the settings (e.g. \"numberFormat\") and the value of the+  --   key.+fromConfigureSpec = unCS+++{-|+Represent the functions that can be chained together and sent to+'Graphics.Vega.VegaLite.configure'.++@since 0.5.0.0+-}++type BuildConfigureSpecs = [ConfigureSpec] -> [ConfigureSpec]++{-|++Top-level Vega-Lite properties. These are the ones that define the core of the+visualization grammar. All properties are created by functions which can be+arranged into seven broad groups:++[Data Properties] These relate to the input data to be visualized. Generated by+'Graphics.Vega.VegaLite.dataFromColumns', 'Graphics.Vega.VegaLite.dataFromRows', 'Graphics.Vega.VegaLite.dataFromUrl', 'Graphics.Vega.VegaLite.dataFromSource',+'Graphics.Vega.VegaLite.dataFromJson', 'Graphics.Vega.VegaLite.dataSequence', 'Graphics.Vega.VegaLite.sphere', and 'Graphics.Vega.VegaLite.graticule'.++[Transform Properties] These indicate that some transformation of input data should+be applied before encoding them visually. Generated by 'Graphics.Vega.VegaLite.transform'+and 'Graphics.Vega.VegaLite.projection' they can include data transformations such as 'Graphics.Vega.VegaLite.filter',+'Graphics.Vega.VegaLite.binAs' and 'Graphics.Vega.VegaLite.calculateAs' and geo transformations of longitude, latitude coordinates+used by marks such as 'Graphics.Vega.VegaLite.Geoshape', 'Graphics.Vega.VegaLite.Point', and 'Graphics.Vega.VegaLite.Line'.++[Mark Properties] These relate to the symbols used to visualize data items. They+are generated by 'Graphics.Vega.VegaLite.mark', and include types such as 'Graphics.Vega.VegaLite.Circle', 'Graphics.Vega.VegaLite.Bar', and 'Graphics.Vega.VegaLite.Line'.++[Encoding Properties] These specify which data elements are mapped to which mark characteristics+(known as /channels/). Generated by 'Graphics.Vega.VegaLite.encoding', they include encodings+such as 'Graphics.Vega.VegaLite.position', 'Graphics.Vega.VegaLite.color', 'Graphics.Vega.VegaLite.size', 'Graphics.Vega.VegaLite.shape', 'Graphics.Vega.VegaLite.text', 'Graphics.Vega.VegaLite.hyperlink', and+'Graphics.Vega.VegaLite.order'.++[Composition Properties] These allow visualization views to be combined to form more+complex visualizations. Generated by 'Graphics.Vega.VegaLite.layer', 'Graphics.Vega.VegaLite.repeat', 'Graphics.Vega.VegaLite.repeatFlow', 'Graphics.Vega.VegaLite.facet', 'Graphics.Vega.VegaLite.facetFlow',+'Graphics.Vega.VegaLite.vlConcat', 'Graphics.Vega.VegaLite.columns', 'Graphics.Vega.VegaLite.hConcat', 'Graphics.Vega.VegaLite.vConcat', 'Graphics.Vega.VegaLite.asSpec', and 'Graphics.Vega.VegaLite.resolve'.++[Interaction Properties] These allow interactions such as clicking, dragging and others+generated via a GUI or data stream to influence the visualization. Generated by+'Graphics.Vega.VegaLite.selection'.++[Supplementary and Configuration Properties] These provide a means to add metadata and+styling to one or more visualizations. Generated by+'Graphics.Vega.VegaLite.name', 'Graphics.Vega.VegaLite.title',+'Graphics.Vega.VegaLite.description', 'Graphics.Vega.VegaLite.background',+'Graphics.Vega.VegaLite.height', 'Graphics.Vega.VegaLite.heightStep',+'Graphics.Vega.VegaLite.width', 'Graphics.Vega.VegaLite.widthStep',+'Graphics.Vega.VegaLite.padding', 'Graphics.Vega.VegaLite.autosize',+'Graphics.Vega.VegaLite.viewBackground', and+'Graphics.Vega.VegaLite.configure'.++Prior to @0.4.0.0@ this was an opaque data type, as the constructors+were not exported. It is suggested that you do not import the+constructors to @VLProperty@ unless you need to transform the+Vega-Lite code in some manner (e.g. because @hvega@ is missing needed+functionality or is buggy).++Note that there is only a very-limited attempt to enforce the Vega-Lite+Schema (e.g. to ensure the required components are provided).++-}++-- based on schema 3.3.0 #/definitions/TopLevelSpec+-- which accepts one of+--    #/definitions/TopLevelUnitSpec+--    #/definitions/TopLevelFacetSpec+--    #/definitions/TopLevelLayerSpec+--    #/definitions/TopLevelRepeatSpec+--    #/definitions/TopLevelConcatSpec+--    #/definitions/TopLevelVConcatSpec+--    #/definitions/TopLevelHConcatSpec++data VLProperty+    = VLAlign+      -- ^ See 'Graphics.Vega.VegaLite.align'.+      --+      --   @since 0.4.0.0+    | VLAutosize+      -- ^ See 'Graphics.Vega.VegaLite.autosize'.+    | VLBackground+      -- ^ See 'Graphics.Vega.VegaLite.background'.+    | VLBounds+      -- ^ See 'Graphics.Vega.VegaLite.bounds'.+      --+      --   @since 0.4.0.0+    | VLCenter+      -- ^ See 'Graphics.Vega.VegaLite.center' and 'Graphics.Vega.VegaLite.centerRC'.+      --+      --   @since 0.4.0.0+    | VLColumns+      -- ^ See 'Graphics.Vega.VegaLite.columns'.+      --+      --   @since 0.4.0.0+    | VLConcat+      -- ^ See 'Graphics.Vega.VegaLite.vlConcat'.+      --+      --   @since 0.4.0.0+    | VLConfig+      -- ^ See 'Graphics.Vega.VegaLite.configure'.+    | VLData+      -- ^ See 'Graphics.Vega.VegaLite.dataFromColumns', 'Graphics.Vega.VegaLite.dataFromJson', 'Graphics.Vega.VegaLite.dataFromRows',+      --   'Graphics.Vega.VegaLite.dataFromSource', 'Graphics.Vega.VegaLite.dataFromUrl', 'Graphics.Vega.VegaLite.dataName', 'Graphics.Vega.VegaLite.dataSequence',+      --   'Graphics.Vega.VegaLite.dataSequenceAs', 'Graphics.Vega.VegaLite.graticule', 'Graphics.Vega.VegaLite.noData', and 'Graphics.Vega.VegaLite.sphere'.+    | VLDatasets+      -- ^ See 'Graphics.Vega.VegaLite.datasets'.+    | VLDescription+      -- ^ See 'Graphics.Vega.VegaLite.description'.+    | VLEncoding+      -- ^ See 'Graphics.Vega.VegaLite.encoding'.+    | VLFacet+      -- ^ See 'Graphics.Vega.VegaLite.facet' and 'Graphics.Vega.VegaLite.facetFlow'.+    | VLHConcat+      -- ^ See 'Graphics.Vega.VegaLite.hConcat'.+    | VLHeight+      -- ^ See 'Graphics.Vega.VegaLite.height' and+      --   'Graphics.Vega.VegaLite.heightStep'.+    | VLLayer+      -- ^ See 'Graphics.Vega.VegaLite.layer'.+    | VLMark+      -- ^ See 'Graphics.Vega.VegaLite.mark'.+    | VLName+      -- ^ See 'Graphics.Vega.VegaLite.name'.+    | VLPadding+      -- ^ See 'Graphics.Vega.VegaLite.padding'.+    | VLProjection+      -- ^ See 'Graphics.Vega.VegaLite.projection'.+    | VLRepeat+      -- ^ See 'Graphics.Vega.VegaLite.repeat' and 'Graphics.Vega.VegaLite.repeatFlow'.+    | VLResolve+      -- ^ See 'Graphics.Vega.VegaLite.resolve'.+    | VLSelection+      -- ^ See 'Graphics.Vega.VegaLite.selection'.+    | VLSpacing+      -- ^ See 'Graphics.Vega.VegaLite.alignRC', 'Graphics.Vega.VegaLite.spacing', and 'Graphics.Vega.VegaLite.spacingRC'.+      --+      --   @since 0.4.0.0+    | VLSpecification+      -- ^ See 'Graphics.Vega.VegaLite.specification'.+    | VLTitle+      -- ^ See 'Graphics.Vega.VegaLite.title'.+    | VLTransform+      -- ^ See 'Graphics.Vega.VegaLite.transform'.+    | VLUserMetadata+      -- ^ see 'Graphics.Vega.VegaLite.usermetadata'.+      --+      --   @since 0.4.0.0+    | VLVConcat+      -- ^ See 'Graphics.Vega.VegaLite.vConcat'.+    | VLViewBackground+      -- ^ See 'Graphics.Vega.VegaLite.viewBackground'.+      --+      --   @since 0.4.0.0+    | VLWidth+      -- ^ See 'Graphics.Vega.VegaLite.width' and+      --   'Graphics.Vega.VegaLite.widthStep'.+++vlPropertyLabel :: VLProperty -> T.Text+vlPropertyLabel VLAlign = "align"+vlPropertyLabel VLAutosize = "autosize"+vlPropertyLabel VLBackground = "background"+vlPropertyLabel VLBounds = "bounds"+vlPropertyLabel VLCenter = "center"+vlPropertyLabel VLColumns = "columns"+vlPropertyLabel VLConcat = "concat"+vlPropertyLabel VLConfig = "config"+vlPropertyLabel VLData = "data"+vlPropertyLabel VLDatasets = "datasets"+vlPropertyLabel VLDescription = "description"+vlPropertyLabel VLEncoding = "encoding"+vlPropertyLabel VLFacet = "facet"+vlPropertyLabel VLHConcat = "hconcat"+vlPropertyLabel VLHeight = "height"+vlPropertyLabel VLLayer = "layer"+vlPropertyLabel VLMark = "mark"+vlPropertyLabel VLName = "name"+vlPropertyLabel VLPadding = "padding"+vlPropertyLabel VLProjection = "projection"+vlPropertyLabel VLRepeat = "repeat"+vlPropertyLabel VLResolve = "resolve"+vlPropertyLabel VLSelection = "selection"+vlPropertyLabel VLSpacing = "spacing"+vlPropertyLabel VLSpecification = "spec"+vlPropertyLabel VLTitle = "title"+vlPropertyLabel VLTransform = "transform"+vlPropertyLabel VLUserMetadata = "usermeta"+vlPropertyLabel VLVConcat = "vconcat"+vlPropertyLabel VLViewBackground = "view"+vlPropertyLabel VLWidth = "width"+++{-|++Convenience type-annotation label to indicate the name, or label,+of a selection. It is expected to be a non-empty string, but there+is __no attempt__ to validate this.++@since 0.5.0.0+-}++type SelectionLabel = T.Text
+ src/Graphics/Vega/VegaLite/Time.hs view
@@ -0,0 +1,242 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Time+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings++Time-related types.++-}++module Graphics.Vega.VegaLite.Time+       ( DateTime(..)+       , MonthName(..)+       , DayName(..)+       , TimeUnit(..)++       -- not for external export+       , timeUnit_++       , dateTimeProperty+       -- , dayLabel+       -- , monthNameLabel+       , timeUnitLabel+       +       ) where++import qualified Data.Text as T++import Data.Aeson ((.=))++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif++import Graphics.Vega.VegaLite.Specification (LabelledSpec)+++timeUnit_ :: TimeUnit -> LabelledSpec+timeUnit_ tu = "timeUnit" .= timeUnitLabel tu+++{-|++Allows a date or time to be represented. This is typically part of a list of+@DateTime@ items to provide a specific point in time. For details see the+<https://vega.github.io/vega-lite/docs/types.html#datetime Vega-Lite documentation>.++There is __no check__ that the provided @Int@ values lie within the+required bounds.++A 'DateTime' value of 'DTDay' or 'DTDayNum' should not be combined with+'DTYear', 'DTQuarter', 'DTMonth', 'DTMonthNum', or 'DTDate'.++-}++data DateTime+    = DTYear Int+    | DTQuarter Int+      -- ^ The quarter of the year (1 to 4, inclusive).+    | DTMonth MonthName+    | DTMonthNum Int+      -- ^ The month number (1 to 12, inclusive).+      --+      --    @since 0.5.0.0+    | DTDate Int+      -- ^ Day of the month (1 to 31, inclusive).+    | DTDay DayName+    | DTDayNum Int+      -- ^ The day number (1 represents Monday, 7 is Sunday).+      --+      --    @since 0.5.0.0+    | DTHours Int+      -- ^ Hour of the day, where 0 is midnight, 1 is 1am, and+      --   23 is 11pm.+    | DTMinutes Int+      -- ^ The minute of an hour (0 to 59, inclusive).+    | DTSeconds Int+      -- ^ The second of a minute (0 to 59, inclusive).+    | DTMilliseconds Int+      -- ^ The milliseconds of a second (0 to 999, inclusive).+++-- | Identifies the day of the week.++data DayName+    = Mon+    | Tue+    | Wed+    | Thu+    | Fri+    | Sat+    | Sun+++-- | Identifies a month of the year.++data MonthName+    = Jan+    | Feb+    | Mar+    | Apr+    | May+    | Jun+    | Jul+    | Aug+    | Sep+    | Oct+    | Nov+    | Dec+++{-|++Describes a unit of time. Useful for encoding and transformations. See the+<https://vega.github.io/vega-lite/docs/timeunit.html Vega-Lite documentation>+for further details.++@+'Graphics.Vega.VegaLite.encoding'+    . 'Graphics.Vega.VegaLite.position' 'Graphics.Vega.VegaLite.X' [ 'Graphics.Vega.VegaLite.PName' "date", 'Graphics.Vega.VegaLite.PmType' 'Graphics.Vega.VegaLite.Temporal', 'Graphics.Vega.VegaLite.PTimeUnit' ('Utc' 'YearMonthDateHours') ]+@+-}++data TimeUnit+    = Year+      -- ^ Year.+    | YearQuarter+      -- ^ Year and quarter.+    | YearQuarterMonth+      -- ^ Year, quarter, and month.+    | YearMonth+      -- ^ Year and month.+    | YearMonthDate+      -- ^ Year, month, and day of month.+    | YearMonthDateHours+      -- ^ Year, month, day of month, and hour of day.+    | YearMonthDateHoursMinutes+      -- ^ Year, month, day of month, hour of day, and minutes.+    | YearMonthDateHoursMinutesSeconds+      -- ^ Year, month, day of month, hour of day, minutes, and seconds.+    | Quarter+      -- ^ Quarter of the year.+    | QuarterMonth+      -- ^ Quarter of the year and month.+    | Month+      -- ^ Month of the year.+    | MonthDate+      -- ^ Month of the year and day of the month.+    | Date+      -- ^ Day of the month (1 to 31).+    | Day+      -- ^ Day of the week.+    | Hours+      -- ^ Hour of the day.+    | HoursMinutes+      -- ^ Hour of the day and minutes.+    | HoursMinutesSeconds+      -- ^ Hour of the day, minutes, and seconds.+    | Minutes+      -- ^ Minutes of the hour.+    | MinutesSeconds+      -- ^ Minutes of the hour and seconds.+    | Seconds+      -- ^ Seconds of the minute.+    | SecondsMilliseconds+      -- ^ Seconds of the minute and milliseconds.+    | Milliseconds+      -- ^ Milliseconds.+    | Utc TimeUnit+      -- ^ Encode a time as UTC (coordinated universal time, independent of local time+      --   zones or daylight saving).+++dateTimeProperty :: DateTime -> LabelledSpec+dateTimeProperty (DTYear y) = "year" .= y+dateTimeProperty (DTQuarter q) = "quarter" .= q+dateTimeProperty (DTMonth mon) = "month" .= monthNameLabel mon+dateTimeProperty (DTMonthNum n) = "month" .= n+dateTimeProperty (DTDate dt) = "date" .= dt+dateTimeProperty (DTDay day) = "day" .= dayLabel day+dateTimeProperty (DTDayNum n) = "day" .= n+dateTimeProperty (DTHours h) = "hours" .= h+dateTimeProperty (DTMinutes m) = "minutes" .= m+dateTimeProperty (DTSeconds s) = "seconds" .= s+dateTimeProperty (DTMilliseconds ms) = "milliseconds" .= ms+++dayLabel :: DayName -> T.Text+dayLabel Mon = "Mon"+dayLabel Tue = "Tue"+dayLabel Wed = "Wed"+dayLabel Thu = "Thu"+dayLabel Fri = "Fri"+dayLabel Sat = "Sat"+dayLabel Sun = "Sun"+++monthNameLabel :: MonthName -> T.Text+monthNameLabel Jan = "Jan"+monthNameLabel Feb = "Feb"+monthNameLabel Mar = "Mar"+monthNameLabel Apr = "Apr"+monthNameLabel May = "May"+monthNameLabel Jun = "Jun"+monthNameLabel Jul = "Jul"+monthNameLabel Aug = "Aug"+monthNameLabel Sep = "Sep"+monthNameLabel Oct = "Oct"+monthNameLabel Nov = "Nov"+monthNameLabel Dec = "Dec"+++timeUnitLabel :: TimeUnit -> T.Text+timeUnitLabel Year = "year"+timeUnitLabel YearQuarter = "yearquarter"+timeUnitLabel YearQuarterMonth = "yearquartermonth"+timeUnitLabel YearMonth = "yearmonth"+timeUnitLabel YearMonthDate = "yearmonthdate"+timeUnitLabel YearMonthDateHours = "yearmonthdatehours"+timeUnitLabel YearMonthDateHoursMinutes = "yearmonthdatehoursminutes"+timeUnitLabel YearMonthDateHoursMinutesSeconds = "yearmonthdatehoursminutesseconds"+timeUnitLabel Quarter = "quarter"+timeUnitLabel QuarterMonth = "quartermonth"+timeUnitLabel Month = "month"+timeUnitLabel MonthDate = "monthdate"+timeUnitLabel Date = "date"+timeUnitLabel Day = "day"+timeUnitLabel Hours = "hours"+timeUnitLabel HoursMinutes = "hoursminutes"+timeUnitLabel HoursMinutesSeconds = "hoursminutesseconds"+timeUnitLabel Minutes = "minutes"+timeUnitLabel MinutesSeconds = "minutesseconds"+timeUnitLabel Seconds = "seconds"+timeUnitLabel SecondsMilliseconds = "secondsmilliseconds"+timeUnitLabel Milliseconds = "milliseconds"+timeUnitLabel (Utc tu) = "utc" <> timeUnitLabel tu
+ src/Graphics/Vega/VegaLite/Transform.hs view
@@ -0,0 +1,545 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++{-|+Module      : Graphics.Vega.VegaLite.Transform+Copyright   : (c) Douglas Burke, 2018-2020+License     : BSD3++Maintainer  : dburke.gw@gmail.com+Stability   : unstable+Portability : CPP, OverloadedStrings++Types related to data transformation.++Note that this does not include some of the \"obvious\" types,+in particular @Operation@ and @Filter@ as these types are+inter-related and end up requiring a number of other types unrelated+to transformations.++-}++module Graphics.Vega.VegaLite.Transform+       ( Operation(..)+       , Window(..)+       , WOperation(..)+       , BinProperty(..)+       , WindowProperty(..)+       , ImputeProperty(..)+       , ImMethod(..)++         -- not for external export+       , aggregate_+       , op_+       , binned_+       , impute_+       , bin+       , binProperty+       , operationSpec+       , windowTS+       , joinAggregateTS+       , imputeTS++       ) where++import qualified Data.Aeson as A+import qualified Data.Text as T++import Data.Aeson ((.=), object, toJSON)+import Data.Maybe (mapMaybe)++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif++import Graphics.Vega.VegaLite.Data+  ( DataValue+  , DataValues+  , dataValueSpec+  , dataValuesSpecs+  )+import Graphics.Vega.VegaLite.Foundation+  ( FieldName+  , SortField+  , sortFieldSpec+  , field_+  , fromT+  , allowNull+  )+import Graphics.Vega.VegaLite.Specification+  ( VLSpec+  , LabelledSpec+  , TransformSpec(..)+  , SelectionLabel+  )+++{-|++Type of aggregation operation. See the+<https://vega.github.io/vega-lite/docs/aggregate.html#ops Vega-Lite documentation>+for more details.++The @Average@ constructor was removed in version @0.4.0.0@; use 'Mean' instead.++-}+data Operation+    = ArgMax (Maybe FieldName)+      -- ^ An input data object containing the maximum field value to be used+      --   in an aggregation operation.+      --+      --   If supplied as part of an encoding aggregation, the parameter+      --   should be 'Just' the name of the field to maximise. When used+      --   as part of a transform the parameter should be 'Nothing' as the+      --   field is specified in the 'Graphics.Vega.VegaLite.aggregate' call.+      --+      --   Encoding example, to find the production budget for the maximum+      --   US grossing film in each genre:+      --+      --   @+      --   'Graphics.Vega.VegaLite.encoding'+      --     . 'Graphics.Vega.VegaLite.position' 'Graphics.Vega.VegaLite.X'+      --                [ 'Graphics.Vega.VegaLite.PName' \"Production_Budget\"+      --                , 'Graphics.Vega.VegaLite.PmType' 'Graphics.Vega.VegaLite.Quantitative'+      --                , 'Graphics.Vega.VegaLite.PAggregate' ('ArgMax' ('Just' \"US_Gross\"))+      --                ]+      --     . 'Graphics.Vega.VegaLite.position' 'Graphics.Vega.VegaLite.Y' ['Graphics.Vega.VegaLite.PName' \"Major_Genre\", 'Graphics.Vega.VegaLite.PmType' 'Graphics.Vega.VegaLite.Nominal']+      --   @+      --+      --   An example of its use as part of an 'Graphics.Vega.VegaLite.aggregate' call:+      --+      --   @+      --   'Graphics.Vega.VegaLite.transform'+      --     . 'Graphics.Vega.VegaLite.aggregate'+      --         [ 'Graphics.Vega.VegaLite.opAs' ('ArgMax' 'Nothing') \"US_Gross\" \"amUSGross\"]+      --         [\"Major_Genre\"]+      --   @+      --+      --   The optional field name was added in the @0.4.0.0@ release.+    | ArgMin (Maybe FieldName)+      -- ^ An input data object containing the minimum field value to be used+      --   in an aggregation operation. See 'ArgMax' for a discussion of the+      --   optional argument.+      --+      --   The optional field name was added in the @0.4.0.0@ release.+    | CI0+      -- ^ Lower 95% confidence interval to be used in an aggregation operation.+    | CI1+      -- ^ Upper 95% confidence interval to be used in an aggregation operation.+    | Count+      -- ^ Total count of data objects to be used in an aggregation operation.+    | Distinct+      -- ^ Count of distinct data objects to be used in an aggregation operation.+    | Max+      -- ^ Maximum field value to be used in an aggregation operation.+    | Mean+      -- ^ Mean field value to be used in an aggregation operation.+    | Median+      -- ^ Median field value to be used in an aggregation operation.+    | Min+      -- ^ 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.+    | Q1+      -- ^ Lower quartile boundary of field values to be used in an aggregation operation.+    | Q3+      -- ^ Upper quartile boundary of field values to be used in an aggregation operation.+    | Stderr+      -- ^ Standard error of field values to be used in an aggregate operation.+    | Stdev+      -- ^ Sample standard deviation of field values to be used in an aggregate operation.+    | StdevP+      -- ^ Population standard deviation of field values to be used in an aggregate operation.+    | Sum+      -- ^ Sum of field values to be used in an aggregate operation.+    | Valid+      -- ^ Count of values that are not @null@, @undefined@, or @NaN@ to be used in an+      -- aggregation operation.+    | Variance+      -- ^ Sample variance of field values to be used in an aggregate operation.+    | VarianceP+      -- ^ Population variance of field values to be used in an aggregate operation.+++-- Unlike Elm, not checking if the string is empty for ArgMin/Max++operationSpec :: Operation -> VLSpec+operationSpec (ArgMax Nothing) = "argmax"+operationSpec (ArgMax (Just s)) = object ["argmax" .= s]+operationSpec (ArgMin Nothing) = "argmin"+operationSpec (ArgMin (Just s)) = object ["argmin" .= s]+operationSpec CI0 = "ci0"+operationSpec CI1 = "ci1"+operationSpec Count = "count"+operationSpec Distinct = "distinct"+operationSpec Max = "max"+operationSpec Mean = "mean"+operationSpec Median = "median"+operationSpec Min = "min"+operationSpec Missing = "missing"+operationSpec Q1 = "q1"+operationSpec Q3 = "q3"+operationSpec Stderr = "stderr"+operationSpec Stdev = "stdev"+operationSpec StdevP = "stdevp"+operationSpec Sum = "sum"+operationSpec Valid = "valid"+operationSpec Variance = "variance"+operationSpec VarianceP = "variancep"+++aggregate_ :: Operation -> LabelledSpec+aggregate_ op = "aggregate" .= operationSpec op++op_ :: Operation -> LabelledSpec+op_ op = "op" .= operationSpec op+++-- | Window transformations.+--+--   @since 0.4.0.0++data Window+    = WAggregateOp Operation+      -- ^ An aggregrate operation to be used in a window transformation.+    | WOp WOperation+      -- ^ Window-specific operation to be used in a window transformation.+    | WParam Int+      -- ^ Numeric parameter for window-only operations that can be parameterised+      --   ('Ntile', 'Lag', 'Lead' and 'NthValue').+    | WField FieldName+      -- ^ Field for which to compute a window operation. Not needed for operations+      --   that do not apply to fields such as 'Count', 'Rank', and 'DenseRank'.+++windowFieldProperty :: Window -> LabelledSpec+windowFieldProperty (WAggregateOp op) = "op" .= operationSpec op+windowFieldProperty (WOp op) = "op" .= wOperationLabel op+windowFieldProperty (WParam n) = "param" .= n+windowFieldProperty (WField f) = field_ f+++-- | Window-specific operation for transformations (for use with 'WOp').+--+--   @since 0.4.0.0++data WOperation+    = RowNumber+      -- ^ Assign consecutive row number to values in a data object to be applied in a window transform.+    | Rank+      -- ^ Rank function to be applied in a window transform.+    | DenseRank+      -- ^ Dense rank function to be applied in a window transform.+    | PercentRank+      -- ^ Percentile of values in a sliding window to be applied in a window transform.+    | CumeDist+      -- ^ Cumulative distribution function to be applied in a window transform.+    | Ntile+      -- ^ Value preceding the current object in a sliding window to be applied in a window transform.+    | Lag+      -- ^ Value preceding the current object in a sliding window to be applied in a window transform.+    | Lead+      -- ^ Value following the current object in a sliding window to be applied in a window transform.+    | FirstValue+      -- ^ First value in a sliding window to be applied in a window transform.+    | LastValue+      -- ^ Last value in a sliding window to be applied in a window transform.+    | NthValue+      -- ^ Nth value in a sliding window to be applied in a window transform.+++wOperationLabel :: WOperation -> T.Text+wOperationLabel RowNumber = "row_number"+wOperationLabel Rank = "rank"+wOperationLabel DenseRank = "dense_rank"+wOperationLabel PercentRank = "percent_rank"+wOperationLabel CumeDist = "cume_dist"+wOperationLabel Ntile = "ntile"+wOperationLabel Lag = "lag"+wOperationLabel Lead = "lead"+wOperationLabel FirstValue = "first_value"+wOperationLabel LastValue = "last_value"+wOperationLabel NthValue = "nth_value"++{-|++Type of binning property to customise. See the+<https://vega.github.io/vega-lite/docs/bin.html Vega-Lite documentation> for+more details.++This is used with: 'Graphics.Vega.VegaLite.binAs', 'Graphics.Vega.VegaLite.DBin', 'Graphics.Vega.VegaLite.FBin', 'Graphics.Vega.VegaLite.HBin', 'Graphics.Vega.VegaLite.MBin', 'Graphics.Vega.VegaLite.OBin',+'Graphics.Vega.VegaLite.PBin', and 'Graphics.Vega.VegaLite.TBin'.++-}++-- based on schema 3.3.0 #/definitions/BinParams++data BinProperty+    = AlreadyBinned Bool+      -- ^ Should the input data be treated as already binned?+      --+      --   @since 0.4.0.0+    | BinAnchor Double+      -- ^ A value in the binned domain at which to anchor the bins, shifting the bin+      --   boundaries if necessary to ensure that a boundary aligns with the anchor+      --   value.+      --+      --   @since 0.4.0.0+    | Base Double+      -- ^ The number base to use for automatic bin determination.+      --+      --   Default is @10@.+    | Divide [Double]+      -- ^ Scale factors indicating allowable subdivisions.+      --+      --   Default is @[5, 2]@.+      --+      --   Prior to @0.4.0.0@ the @Divide@ constructor took two numbers.+    | Extent Double Double+      -- ^ The range (minimum, maximum) of the desired bin values.+    | MaxBins Int+      -- ^ The maxium number of bins.+      --+      --   Default is @6@ for 'Graphics.Vega.VegaLite.row', 'Graphics.Vega.VegaLite.column', and 'Graphics.Vega.VegaLite.shape' channels,+      --   @10@ otherwise.+    | MinStep Double+      -- ^ A minimum allowable step size.+    | Nice Bool+      -- ^ If @True@, the bin boundaries are adjusted to use human-friendly values,+      --   such as multiples of ten.+      --+      --   Default is @True@.+    | SelectionExtent SelectionLabel+      -- ^ Set the range based on an interactive selection. The label+      --   must reference an interval selection, but this constraint is+      --   /not enforced/ at compile or run time.+      --+      --   @+      --   sel = 'Graphics.Vega.VegaLite.selection'+      --         . 'Graphics.Vega.VegaLite.select' \"brush\" 'Graphics.Vega.VegaLite.Interval' [ 'Graphics.Vega.VegaLite.Encodings' [ 'Graphics.Vega.VegaLite.ChX' ] ]+      --   enc = 'Graphics.Vega.VegaLite.encoding'+      --         . 'Graphics.Vega.VegaLite.position' 'Graphics.Vega.VegaLite.X' [ 'Graphics.Vega.VegaLite.PName' \"temperature\"+      --                      , 'Graphics.Vega.VegaLite.PmType' 'Graphics.Vega.VegaLite.Quantitative'+      --                      , 'Graphics.Vega.VegaLite.PBin' [ 'SelectionExtent' \"brush\" ]+      --                      ]+      --   @+      --+      --   @since 0.5.0.0+    | Step Double+      -- ^ The step size to use between bins.+      --+      --   If specified, 'MaxBins' and other related options are ignored.+    | Steps [Double]+      -- ^ Pick the step size from this list.+++binProperty :: BinProperty -> LabelledSpec+binProperty (AlreadyBinned b) = "binned" .= b+binProperty (BinAnchor x) = "anchor" .= x+binProperty (Base x) = "base" .= x+binProperty (Divide xs) = "divide" .= xs+binProperty (Extent mn mx) = "extent" .= [ mn, mx ]+binProperty (SelectionExtent s) = "extent" .= object [ "selection" .= s ]+binProperty (MaxBins n) = "maxbins" .= n+binProperty (MinStep x) = "minstep" .= x+binProperty (Nice b) = "nice" .= b+binProperty (Step x) = "step" .= x+binProperty (Steps xs) = "steps" .= xs+++bin :: [BinProperty] -> LabelledSpec+bin [] = "bin" .= True+bin xs = "bin" .= object (map binProperty xs)++binned_ :: LabelledSpec+binned_ = "bin" .= fromT "binned"+++-- | Properties for a window transform.+--+--   @since 0.4.0.0++data WindowProperty+    = WFrame (Maybe Int) (Maybe Int)+      -- ^ Moving window for use by a window transform. When a number is+      --   given, via @Just@, then it indicates the offset from the current+      --   data object. A @Nothing@ indicates an un-bounded number of rows+      --   preceding or following the current data object.+    | WIgnorePeers Bool+      -- ^ Should the sliding window in a window transform ignore peer+      --   values (those considered identical by the sort criteria).+    | WGroupBy [FieldName]+      -- ^ The fields for partitioning data objects in a window transform+      --   into separate windows. If not specified, all points will be in a+      --   single group.+    | WSort [SortField]+      -- ^ Comparator for sorting data objects within a window transform.+++-- This is different to how Elm's VegaLite handles this (as of version 1.12.0)+-- Helpers for windowPropertySpec++wpFrame , wpIgnorePeers, wpGroupBy, wpSort :: WindowProperty -> Maybe VLSpec+wpFrame (WFrame m1 m2) = Just (toJSON [allowNull m1, allowNull m2])+wpFrame _ = Nothing++wpIgnorePeers (WIgnorePeers b) = Just (toJSON b)+wpIgnorePeers _ = Nothing++wpGroupBy (WGroupBy fs) = Just (toJSON fs)+wpGroupBy _ = Nothing++wpSort (WSort sfs) = Just (toJSON (map sortFieldSpec sfs))+wpSort _ = Nothing++windowTS ::+  [([Window], FieldName)]+  -> [WindowProperty]+  -> TransformSpec+windowTS wss wps =+  let addField n a = case mapMaybe a wps of+                       [x] -> [n .= x]+                       _ -> []++      winFieldDef (ws, out) = object ("as" .= out : map windowFieldProperty ws)++      fields = [ "window" .= map winFieldDef wss ]+               <> addField "frame" wpFrame+               <> addField "ignorePeers" wpIgnorePeers+               <> addField "groupby" wpGroupBy+               <> addField "sort" wpSort++  in TS (object fields)+++joinAggregateTS :: [VLSpec] -> [WindowProperty] -> TransformSpec+joinAggregateTS ops wps =+  let addField n a = case mapMaybe a wps of+                       [x] -> [n .= x]+                       _ -> []++      fields = [ "joinaggregate" .= ops ]+               <> addField "frame" wpFrame+               <> addField "ignorePeers" wpIgnorePeers+               <> addField "groupby" wpGroupBy+               <> addField "sort" wpSort++  in TS (object fields)+++-- | This is used with 'Graphics.Vega.VegaLite.impute' and 'Graphics.Vega.VegaLite.PImpute'.+--+--   @since 0.4.0.0++data ImputeProperty+    = ImFrame (Maybe Int) (Maybe Int)+      -- ^ 1d window over which data imputation values are generated. The two+      --   parameters should either be @Just@ a number indicating the offset from the current+      --   data object, or @Nothing@ to indicate unbounded rows preceding or following the+      --   current data object.+    | ImKeyVals DataValues+      -- ^ Key values to be considered for imputation.+    | ImKeyValSequence Double Double Double+      -- ^ Key values to be considered for imputation as a sequence of numbers between+      --   a start (first parameter), to less than an end (second parameter) in steps of+      --   the third parameter.+    | ImMethod ImMethod+      -- ^ How is the imputed value constructed.+      --+      --   When using @ImMethod 'ImValue'@, the replacement value is+      --   set with 'ImNewValue'.+    | ImGroupBy [FieldName]+      -- ^ Allow imputing of missing values on a per-group basis. For use with the impute+      --   transform only and not a channel encoding.+    | ImNewValue DataValue+      -- ^ The replacement value (when using @ImMethod 'ImValue'@).+++imputeProperty :: ImputeProperty -> LabelledSpec+imputeProperty (ImFrame m1 m2) = "frame" .= map allowNull [m1, m2]+imputeProperty (ImKeyVals dVals) = "keyvals" .= dataValuesSpecs dVals+imputeProperty (ImKeyValSequence start stop step) =+  "keyvals" .= object ["start" .= start, "stop" .= stop, "step" .= step]+imputeProperty (ImMethod method) = "method" .= imMethodLabel method+imputeProperty (ImNewValue dVal) = "value" .= dataValueSpec dVal+imputeProperty (ImGroupBy _) = "groupby" .= A.Null+++imputePropertySpecFrame, imputePropertySpecKeyVals,+  imputePropertySpecKeyValSequence, imputePropertySpecGroupBy,+  imputePropertySpecMethod, imputePropertySpecValue :: ImputeProperty -> Maybe VLSpec++imputePropertySpecFrame (ImFrame m1 m2) = Just (toJSON (map allowNull [m1, m2]))+imputePropertySpecFrame _ = Nothing++imputePropertySpecKeyVals (ImKeyVals dVals) = Just (toJSON (dataValuesSpecs dVals))+imputePropertySpecKeyVals _ = Nothing++imputePropertySpecKeyValSequence (ImKeyValSequence start stop step) =+  let obj = ["start" .= start, "stop" .= stop, "step" .= step]+  in Just (object obj)+imputePropertySpecKeyValSequence _ = Nothing++imputePropertySpecGroupBy (ImGroupBy fields) = Just (toJSON fields)+imputePropertySpecGroupBy _ = Nothing++imputePropertySpecMethod (ImMethod method) = Just (toJSON (imMethodLabel method))+imputePropertySpecMethod _ = Nothing++imputePropertySpecValue (ImNewValue dVal) = Just (dataValueSpec dVal)+imputePropertySpecValue _ = Nothing+++impute_ :: [ImputeProperty] -> LabelledSpec+impute_ ips = "impute" .= object (map imputeProperty ips)+++imputeTS ::+  FieldName+  -- ^ The data field to process.+  -> FieldName+  -- ^ The key field to uniquely identify data objects within a group.+  -> [ImputeProperty]+  -- ^ Define how the imputation works.+  -> TransformSpec+imputeTS field key imProps =+  let addField n a = case mapMaybe a imProps of+                       [x] -> [n .= x]+                       _ -> []++      fields = [ "impute" .= field+               , "key" .= key ]+               <> addField "frame" imputePropertySpecFrame+               -- TODO: can we combine the keyvals options?+               <> addField "keyvals" imputePropertySpecKeyVals+               <> addField "keyvals" imputePropertySpecKeyValSequence+               <> addField "method" imputePropertySpecMethod+               <> addField "groupby" imputePropertySpecGroupBy+               <> addField "value" imputePropertySpecValue++  in TS (object fields)+++-- | Imputation method to use when replacing values.+--+--   @since 0.4.0.0++data ImMethod+  = ImMin+    -- ^ Use the minimum value.+  | ImMax+    -- ^ Use the maximum value.+  | ImMean+    -- ^ Use the mean value.+  | ImMedian+    -- ^ Use the median value.+  | ImValue+    -- ^ Use a replacement value (set with @ImNewValue@).+++imMethodLabel :: ImMethod -> T.Text+imMethodLabel ImMin = "min"+imMethodLabel ImMax = "max"+imMethodLabel ImMean = "mean"+imMethodLabel ImMedian = "median"+imMethodLabel ImValue = "value"
stack.yaml view
@@ -5,4 +5,4 @@  extra-deps: [] -resolver: lts-14.18+resolver: lts-14.23
tests/AxisTests.hs view
@@ -18,9 +18,14 @@             , ("axis4", axis4)             , ("axis5", axis5)             , ("axis6", axis6)-            -- , ("axis7", axis7)  require AxLabelExpr support (VL 4)-            -- , ("axis8", axis8)  require AxLabelExpr support (VL 4)+            , ("axis7", axis7)+            , ("axis8", axis8)+            , ("axisOverlapNone", axisOverlapNone)+            , ("axisOverlapParity", axisOverlapParity)+            , ("axisOverlapGreedy", axisOverlapGreedy)             , ("zorder", zorder)+            , ("responsiveWidth", responsiveWidth)+            , ("responsiveHeight", responsiveHeight)             ]  @@ -138,7 +143,6 @@     toVegaLite [ temporalData [], enc [], mark Line [ MPoint (PMMarker []) ] ]  -{- axis7 :: VegaLite axis7 =   let enc = encoding@@ -162,9 +166,34 @@   in     toVegaLite [ simpleData [], enc [], mark Line [ MPoint (PMMarker []) ] ] --} +overlap :: OverlapStrategy -> VegaLite+overlap strat =+  let dvals = dataFromColumns []+              . dataColumn "x" (Numbers [ 0.1, 0.11, 0.2, 0.21, 0.5 ])+              . dataColumn "y" (Numbers [ 100, 101, 102, 103, 101 ]) +      axisOpts = PAxis [ AxLabelOverlap strat+                       , AxLabelFontSize 20+                       ]++      enc = encoding+            . position X [ PName "x", PmType Quantitative, axisOpts ]+            . position Y [ PName "y", PmType Quantitative, axisOpts ]++  in toVegaLite [ dvals [], enc [], mark Circle [] ]+++axisOverlapNone :: VegaLite+axisOverlapNone = overlap ONone++axisOverlapParity :: VegaLite+axisOverlapParity = overlap OParity++axisOverlapGreedy :: VegaLite+axisOverlapGreedy = overlap OGreedy++ -- From -- https://github.com/gicentre/elm-vegalite/issues/15#issuecomment-524527125 --@@ -191,3 +220,17 @@                 , enc []                 , mark Circle [ MSize 5000, MOpacity 1 ]                 ]+++responsive :: PropertySpec -> VegaLite+responsive prop =+  let enc = encoding+            . position X [PName "x", PmType Quantitative]+            . position Y [PName "y", PmType Quantitative]++  in toVegaLite [ prop, simpleData [], enc []+                , mark Line [MPoint (PMMarker [])] ]++responsiveWidth, responsiveHeight :: VegaLite+responsiveWidth = responsive widthOfContainer+responsiveHeight = responsive heightOfContainer
tests/ColorTests.hs view
@@ -51,7 +51,7 @@             ]  -chart :: T.Text -> ([a] -> [LabelledSpec]) -> VegaLite+chart :: T.Text -> ([a] -> [EncodingSpec]) -> VegaLite chart desText enc =     let des = description desText 
tests/CompositeTests.hs view
@@ -24,8 +24,22 @@             , ("errorbar1", errorbar1)             , ("errorbar2", errorbar2)             , ("errorbar3", errorbar3)+            , ("errorbar4", errorbar4)+            , ("errorbar5", errorbar5)+            , ("errorbar6", errorbar6)+            , ("errorbar7", errorbar7)             ] ++-- help in converting from the Elm version+pName :: T.Text -> PositionChannel+pName = PName++pOrdinal, pQuant :: PositionChannel+pOrdinal = PmType Ordinal+pQuant = PmType Quantitative++ bPlot :: MarkErrorExtent -> VegaLite bPlot ext =     let@@ -204,3 +218,99 @@         , dataFromUrl "https://vega.github.io/vega-lite/data/barley.json" []         , layer [ specErrorBars, specPoints ]         ]+++yieldData :: [DataColumn] -> Data+yieldData =+  dataFromColumns []+  . dataColumn "yieldError" (Numbers [ 7.55, 6.98, 3.92, 11.97 ])+  . dataColumn "yieldError2" (Numbers [ -10.55, -3.98, -0.92, -15.97 ])+  . dataColumn "yield" (Numbers [ 32.4, 30.97, 33.96, 30.45 ])+  . dataColumn "variety" (Strings [ "Glabron", "Manchuria", "No. 457", "No. 462" ])++  +errorbar4 :: VegaLite+errorbar4 =+  let des = description "Symetric error bars encoded with xError channel"++      specErrorBars = asSpec [ mark ErrorBar [ MTicks [] ], encErrorBars [] ]++      encErrorBars = encoding+                     . position X [ pName "yield", pQuant+                                  , PScale [ SZero False ] ]+                     . position Y [ pName "variety", pOrdinal ]+                     . position XError [ pName "yieldError" ]++      specPoints = asSpec [ mark Point [ MFilled True, MColor "black" ]+                          , encPoints [] ]++      encPoints = encoding+                  . position X [ pName "yield", pQuant ]+                  . position Y [ pName "variety", pOrdinal ]++  in toVegaLite [ des, yieldData []+                , layer [ specErrorBars, specPoints ]+                ]+++errorbar5 :: VegaLite+errorbar5 =+  let des = description "Asymetric error bars encoded with xError and xError2 channels"+  +      specErrorBars = asSpec [ mark ErrorBar [ MTicks [] ]+                             , encErrorBars [] ]++      encErrorBars =+        encoding+        . position X [ pName "yield", pQuant, PScale [ SZero False ] ]+        . position Y [ pName "variety", pOrdinal ]+        . position XError [ pName "yieldError" ]+        . position XError2 [ pName "yieldError2" ]++      specPoints = asSpec [ mark Point [ MFilled True, MColor "black" ]+                          , encPoints [] ]++      encPoints = encoding+                  . position X [ pName "yield", pQuant ]+                  . position Y [ pName "variety", pOrdinal ]++  in toVegaLite [ des, yieldData [], layer [ specErrorBars, specPoints ] ]+++errorbar6 :: VegaLite+errorbar6 =+  let des = description "Symetric error bars encoded with yError channel"++      specErrorBars = asSpec [ mark ErrorBar [ MTicks [] ], encErrorBars [] ]+      encErrorBars = encoding+                     . position Y [ pName "yield", pQuant, PScale [ SZero False ] ]+                     . position X [ pName "variety", pOrdinal ]+                     . position YError [ pName "yieldError" ]++      specPoints = asSpec [ mark Point [ MFilled True, MColor "black" ]+                          , encPoints [] ]+      encPoints = encoding+                  . position Y [ pName "yield", pQuant ]+                  . position X [ pName "variety", pOrdinal ]++  in toVegaLite [ des, yieldData [], layer [ specErrorBars, specPoints ] ]+++errorbar7 :: VegaLite+errorbar7 =+  let des = description "Asymetric error bars encoded with yError and yError2 channels"++      specErrorBars = asSpec [ mark ErrorBar [ MTicks [] ], encErrorBars [] ]+      encErrorBars = encoding+                     . position Y [ pName "yield", pQuant, PScale [ SZero False ] ]+                     . position X [ pName "variety", pOrdinal ]+                     . position YError [ pName "yieldError" ]+                     . position YError2 [ pName "yieldError2" ]++      specPoints = asSpec [ mark Point [ MFilled True, MColor "black" ]+                          , encPoints [] ]+      encPoints = encoding+                  . position Y [ pName "yield", pQuant ]+                  . position X [ pName "variety", pOrdinal ]++  in toVegaLite [ des, yieldData [], layer [ specErrorBars, specPoints ] ]
tests/ConditionalTests.hs view
@@ -7,11 +7,16 @@  import Graphics.Vega.VegaLite +import Data.Function ((&)) import Prelude hiding (filter)  testSpecs :: [(String, VegaLite)] testSpecs = [ ("markCondition1", markCondition1)             , ("markCondition2", markCondition2)+            , ("axisCondition1", axisCondition1)+            , ("axisCondition2", axisCondition2)+            , ("axisCondition3", axisCondition3)+            , ("axisDateCondition1", axisDateCondition1)             , ("selectionCondition1", selectionCondition1)             , ("selectionCondition2", selectionCondition2)             , ("selectionCondition3", selectionCondition3)@@ -29,7 +34,7 @@          config =             configure-                . configuration (RemoveInvalid False)+                . configuration (MarkStyle [ MRemoveInvalid False ])          enc =             encoding@@ -45,7 +50,12 @@                         [ MString "#0099ee" ]                     ]     in-    toVegaLite [ config [], dataVals, mark Point [], enc [] ]+    toVegaLite [ config []+               , dataVals+               -- Vega-Lite 4 turned off tooltips by default, so+               -- enable them here+               , mark Point [ MTooltip TTEncoding ]+               , enc [] ]   markCondition2 :: VegaLite@@ -69,10 +79,88 @@     in     toVegaLite [ width 400, dataVals [], mark Circle [ MSize 800 ], enc [] ] ++axisTest :: [AxisProperty] -> VegaLite+axisTest axConds =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []++      enc = encoding+                . position X+                    [ PName "IMDB_Rating"+                    , PmType Quantitative+                    , PAxis (AxTickCount 20 : axConds)+                    ]+                . position Y [ PName "Rotten_Tomatoes_Rating", PmType Quantitative ]++  in toVegaLite [ width 600, height 600, dvals, mark Point [ MOpacity 0.1 ], enc [] ]+++axisCondition1 :: VegaLite+axisCondition1 =+  axisTest [ AxDataCondition (Expr "datum.value <= 5") (CAxGridDash [ 5, 5 ] [])+           , AxDataCondition (Expr "datum.value <= 7") (CAxGridColor "green" "red")+           ]+++axisCondition2 :: VegaLite+axisCondition2 =+  axisTest [ AxDataCondition (Expr "datum.value <= 2") (CAxTickColor "red" "blue")+           , AxDataCondition (Expr "datum.value >=8") (CAxTickOpacity 0.3 0.8)+           , AxDataCondition (Expr "datum.label =='4.0'") (CAxTickWidth 5 2)+           , AxDataCondition (Expr "(datum.value >= 5) && (datum.value <= 8)")+                              (CAxTickDash [2, 2] [])+           {- Vega-Embed (Early Jan 2020) doesn't seem to display this well+           , AxDataCondition (Expr "(datum.value >= 3) && (datum.value <= 7)")+                              (CAxTickDashOffset 4 0)+           -}+           ]+++axisCondition3 :: VegaLite+axisCondition3 =+  axisTest [ AxDataCondition (Expr "datum.value <= 2") (CAxLabelColor "red" "blue")+           , AxDataCondition (Expr "datum.value <= 1") (CAxLabelAlign AlignRight AlignLeft)+           , AxDataCondition (Expr "datum.value <= 3") (CAxLabelBaseline AlignTop AlignBottom)+           , AxDataCondition (Expr "datum.value <= 4") (CAxLabelFont "serif" "sans-serif")+           , AxDataCondition (Expr "datum.value <= 6") (CAxLabelFontSize 12 18)+           , AxDataCondition (Expr "datum.value <=8") (CAxLabelFontStyle "normal" "italic")+           , AxDataCondition (Expr "datum.label =='4.0'") (CAxLabelFontWeight Bold W100)+           , AxDataCondition (Expr "datum.value >=9") (CAxLabelOpacity 0.3 0.8)+           ]+++-- add a basic test of date handling (so that I can check the example given in the+-- documentation, or at least one similar to it, even if in this case it affects+-- all grid lines).+--+axisDateCondition1 :: VegaLite+axisDateCondition1 =+  let dataVals = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []++      enc =+        encoding+          . position X [ PName "Year"+                       , PmType Temporal+                       , PTimeUnit Year+                       , PAxis [ AxDataCondition+                                 (FEqual "value" (DateTime [DTMonth Jan, DTDate 1])+                                   & FilterOpTrans (MTimeUnit MonthDate))+                                 (CAxGridWidth 4 1)+                               ]+                       ]+          . position Y [ PName "Miles_per_Gallon"+                       , PmType Quantitative+                       , PScale [ SZero False ]+                       ]++      mopts = [ MExtent Iqr, MInterpolate Monotone, MBorders [] ]++  in toVegaLite [ width 600, dataVals, enc [], mark ErrorBand mopts ]++ selectionCondition1 :: VegaLite selectionCondition1 =-    let-        dataVals =+    let dataVals =             dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []          sel =
tests/ConfigTests.hs view
@@ -25,8 +25,18 @@             , ("mark1", markCfg1)             , ("mark2", markCfg2)             , ("padding", paddingCfg)+            , ("paddingx", paddingXCfg)+            , ("paddingy", paddingYCfg)+            , ("paddingContent", paddingCntCfg)+            , ("paddingNone", paddingNoneCfg)+            , ("paddingPad", paddingPadCfg)+            , ("paddingPadding", paddingPaddingCfg)+            , ("paddingResize", paddingResizeCfg)             , ("vbTest", vbTest)             , ("axisCfg1", axisCfg1)+            , ("titleCfg1", titleCfg1)+            , ("titleCfg2", titleCfg2)+            , ("titleCfg3", titleCfg3)             ]  singleVis :: ([a] -> (VLProperty, VLSpec)) -> VegaLite@@ -153,6 +163,7 @@                         , ( "mySecondStyle", [ MFill "black", MStroke "blue" ] )                         ]                     )+                . configuration (View [ ViewBackgroundStyle [ VBFill (Just "#feb") ] ])          streamSpec =             asSpec@@ -209,14 +220,26 @@         & compositeVis  -paddingCfg :: VegaLite-paddingCfg =-    configure-        . configuration (Autosize [ AFit ])-        . configuration (Padding (PEdges 90 60 30 0))-        & singleVis+paddingTest :: Autosize -> VegaLite+paddingTest a =+  configure+  . configuration (Autosize [ a ])+  . configuration (Padding (PEdges 90 60 30 0))+  & singleVis  +paddingCfg, paddingXCfg, paddingYCfg, paddingCntCfg, paddingNoneCfg,+  paddingPadCfg, paddingPaddingCfg, paddingResizeCfg:: VegaLite+paddingCfg = paddingTest AFit+paddingXCfg = paddingTest AFitX+paddingYCfg = paddingTest AFitY+paddingCntCfg = paddingTest AContent+paddingNoneCfg = paddingTest ANone+paddingPadCfg = paddingTest APad+paddingPaddingCfg = paddingTest APadding+paddingResizeCfg = paddingTest AResize++ axisCfg1 :: VegaLite axisCfg1 =     configure@@ -227,3 +250,63 @@                              , TitleAnchor AEnd                              ])        & singleVis+++titleOpts :: [PropertySpec]+titleOpts =+  [ dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" [],+    width 200+  , height 200+  , mark Circle []+  , encoding+      . position X [ PName "Horsepower"+                   , PmType Quantitative ]+      . position Y [ PName "Miles_per_Gallon"+                   , PmType Quantitative ]+      $ []+  ]+++titleCfg1 :: VegaLite+titleCfg1 =+  toVegaLite+    ((title "Car\nScatter" [ TSubtitle "A subtitle\nalso over two lines" ])+     : titleOpts)+++cfgOpts :: [TitleConfig]+cfgOpts =+  [ TAnchor AEnd+  , TSubtitleColor "red"+  , TSubtitleFont "serif"+  , TSubtitleFontSize 10+  , TSubtitleFontStyle "italic"+  , TSubtitleFontWeight W900+  , TSubtitleLineHeight 18+  , TSubtitlePadding 60+  , TLineHeight 20+  , TdX (-30)+  , TdY (10)+  ]++subtitle :: TitleConfig+subtitle = TSubtitle "A subtitle\nalso over two lines"++titleCfg2 :: VegaLite+titleCfg2 =+  toVegaLite+    ((title "Car\nScatter"+      (subtitle : cfgOpts))+      : titleOpts)+++titleCfg3 :: VegaLite+titleCfg3 =+  let cfg = configure+                . configuration+                    (TitleStyle cfgOpts)++  in toVegaLite+     ( [ cfg []+       , title "Car\nScatter" [ subtitle ]+       ] ++ titleOpts )
tests/DataTests.hs view
@@ -33,6 +33,8 @@             , ("geodata2", geodata2)             , ("flatten1", flatten1)             , ("fold1", fold1)+            , ("pivot1", pivot1)+            , ("pivotDocs", pivotDocs)             , ("impute1", impute1)             , ("impute2", impute2)             , ("impute3", impute3)@@ -51,13 +53,15 @@             , ("filter2", filter2)             , ("annotate1", annotate1)             , ("null1", null1)+            -- , ("key1", key1)             ]   -- We do not provide these in hvega, so define them here to make copying -- the Elm tests over easier. ---pOrdinal, pQuant :: PositionChannel+pNominal, pOrdinal, pQuant :: PositionChannel+pNominal = PmType Nominal pOrdinal = PmType Ordinal pQuant = PmType Quantitative @@ -315,6 +319,44 @@     toVegaLite [ dvals [], trans [], mark Bar [], enc [] ]  +pivot1 :: VegaLite+pivot1 =+  let dvals = dataFromColumns []+              . dataColumn "country" (Strings [ "USA", "USA", "Canada", "Canada" ])+              . dataColumn "medalType" (Strings [ "gold", "silver", "gold", "silver" ])+              . dataColumn "count" (Numbers [ 10, 20, 7, 26 ])++      trans = transform+              . pivot "medalType" "count" [ PiGroupBy [ "country" ] ]++      enc = encoding+            . position X [ pName "country", pNominal ]+            . position Y [ PRepeat Flow, pQuant ]+            . color [ MName "country", MmType Nominal ]++      spec = asSpec [ dvals [], trans [], enc [], mark Bar [] ]++  in toVegaLite [ repeatFlow [ "gold", "silver" ], specification spec ]+++-- example from the pivot documentation+pivotDocs :: VegaLite+pivotDocs =+  let dvals = dataFromColumns []+              . dataColumn "city" (Strings [ "Bristol", "Bristol", "Sheffield", "Sheffield", "Glasgow", "Glasgow" ])+              . dataColumn "temperature" (Numbers [ 12, 14, 11, 13, 7, 10 ])+              . dataColumn "year" (Numbers [ 2017, 2018, 2017, 2018, 2017, 2018 ])++      trans = transform+              . pivot "year" "temperature" [ PiGroupBy [ "city" ] ]++      enc = encoding+            . position X [ pName "2017", pQuant ]+            . position Y [ pName "city", pNominal ]++  in toVegaLite [ dvals [], trans [], enc [], mark Circle [] ]++ imputeData :: [DataColumn] -> Data imputeData =     dataFromColumns []@@ -624,3 +666,26 @@                  . dataRow [("x", Number 7), ("y", Number 20)]                  $ []              ]+++{-++In adding this test I found the output did not validate against+version 4.0.2, so I've left out for now++key1 :: VegaLite+key1 =+  let dvals = dataFromColumns []+                . dataColumn "x1" (Numbers [ 4, 5, 6 ])+                . dataColumn "x2" (Numbers [ 5, 6, 8 ])+                . dataColumn "y" (Numbers [ 2, 2, 5 ])+                . dataColumn "flag" (Strings [ "good", "bad", "good" ])++      enc = encoding+             . position X [ PName "x1", PmType Quantitative ]+             . position Y [ PName "y", PmType Quantitative ]+             . keyChannel "flag"++  in toVegaLite [ dvals [], enc [], mark Line [] ]++-}
tests/FillStrokeTests.hs view
@@ -26,9 +26,15 @@             , ("combined3", combined3)             , ("geo1", geo1)             , ("geo2", geo2)+            , ("gradient1", gradient1)+            , ("gradient2", gradient2)+            , ("gradient3", gradient3)+            , ("gradientr1", gradientr1)+            , ("gradientr2", gradientr2)+            , ("gradientr3", gradientr3)             ] -encChart :: ([a] -> [LabelledSpec]) -> VegaLite+encChart :: ([a] -> [EncodingSpec]) -> VegaLite encChart extraEnc =     let         dataVals =@@ -105,3 +111,99 @@         , dataFromJson geojson []         , mark Geoshape []         ]+++gradientTest :: PropertySpec -> VegaLite+gradientTest markType =+  let dvals = dataFromColumns []+              . dataColumn "cat" (Strings [ "a", "b", "c", "d" ])+              . dataColumn "value" (Numbers [ 10, 5, 20, 8 ])++      enc = encoding+            . position X [ PName "cat", PmType Nominal ]+            . position Y [ PName "value", PmType Quantitative ]++  in toVegaLite [ width 200, dvals [], enc [], markType ]+++gradient1 :: VegaLite+gradient1 =+  let markType = mark Bar [ MColorGradient GrLinear stops opts ]+      stops = [ (0, "red"), (0.4, "orange"), (1, "blue") ]+      opts = [ GrX1 1+             , GrX2 1+             , GrY1 0+             , GrY2 1+             ]++  in gradientTest markType+++gradient2 :: VegaLite+gradient2 =+  let markType = mark Bar [ MColorGradient GrLinear stops opts ]+      stops = [ (0, "red"), (1, "blue") ]+      opts = [ GrX1 0+             , GrX2 1+             , GrY1 1+             , GrY2 1+             ]++  in gradientTest markType+++gradient3 :: VegaLite+gradient3 =+  let markType = mark Bar [ MColorGradient GrLinear stops opts ]+      stops = [ (1, "red"), (0, "blue") ]+      opts = [ GrX1 0+             , GrX2 1+             , GrY1 0+             , GrY2 1+             ]++  in gradientTest markType+++gradientr1 :: VegaLite+gradientr1 =+  let markType = mark Circle [ MSize 1000+                             , MColorGradient GrRadial stops opts ]+      stops = [ (0, "red"), (0.5, "white"), (1, "blue") ]+      opts = [ ]++  in gradientTest markType+++-- these are the defaults, so they should be the same as r1+gradientr2 :: VegaLite+gradientr2 =+  let markType = mark Circle [ MSize 1000+                             , MColorGradient GrRadial stops opts ]+      stops = [ (0, "red"), (1, "blue"), (0.5, "white") ]+      opts = [ GrX1 0.5+             , GrX2 0.5+             , GrY1 0.5+             , GrY2 0.5+             ]++  in gradientTest markType+++-- not sure if these options make sense, but they are valid according to+-- the Vega-Lite 4.0.2 spec so leave them be.+--+gradientr3 :: VegaLite+gradientr3 =+  let markType = mark Circle [ MSize 1000+                             , MColorGradient GrRadial stops opts ]+      stops = [ (0, "red"), (1, "blue"), (0.5, "white") ]+      opts = [ GrX1 0.2+             , GrX2 0.8+             , GrY1 0.7+             , GrY2 0.3+             , GrR1 0.2+             , GrR2 0.4+             ]++  in gradientTest markType
tests/Gallery/Advanced.hs view
@@ -9,7 +9,9 @@ import Graphics.Vega.VegaLite  import Prelude hiding (filter, lookup)+import Data.Aeson (Value, toJSON) + testSpecs :: [(String, VegaLite)] testSpecs = [ ("advanced1", advanced1)             , ("advanced2", advanced2)@@ -20,9 +22,33 @@             , ("advanced7", advanced7)             , ("advanced8", advanced8)             , ("advanced9", advanced9)+            , ("density1", density1)+            , ("density2", density2)+            , ("filter1", filter1)+            , ("filter2", filter2)+            , ("transform1", transform1)+            , ("layered1", layered1)+            , ("layered2", layered2)+            , ("layered3", layered3)+            , ("benchmark", benchmark)             ]  +-- helpers+--+pQuant, pNominal, pOrdinal, pTemporal :: PositionChannel+pQuant = PmType Quantitative+pNominal = PmType Nominal+pOrdinal = PmType Ordinal+pTemporal = PmType Temporal++fNominal :: FacetChannel+fNominal = FmType Nominal++mNominal :: MarkChannel+mNominal = MmType Nominal++ advanced1 :: VegaLite advanced1 =     let@@ -44,10 +70,10 @@         enc =             encoding                 . position X [ PName "PercentOfTotal", PmType Quantitative, PAxis [ AxTitle "% of total time" ] ]-                . position Y [ PName "Activity", PmType Nominal, PScale [ SRangeStep (Just 12) ] ]+                . position Y [ PName "Activity", PmType Nominal ]     in     toVegaLite-        [ desc, dvals [], trans [], mark Bar [], enc [] ]+        [ desc, dvals [], trans [], mark Bar [], heightStep 12, enc [] ]   advanced2 :: VegaLite@@ -317,30 +343,24 @@         ]  +-- advanced9 in elm advanced7 :: VegaLite advanced7 =-    let-        des =-            description "Using the lookup transform to combine data"+  let des = description "Using the lookup transform to combine data"+      groupData = dataFromUrl "https://vega.github.io/vega-lite/data/lookup_groups.csv" []+      peopleData = dataFromUrl "https://vega.github.io/vega-lite/data/lookup_people.csv" [] -        dvals =-            dataFromUrl "https://vega.github.io/vega-lite/data/lookup_groups.csv"+      trans = transform+              . lookup "person" peopleData "name" (LuFields [ "age", "height" ]) -        trans =-            transform-                . lookup "person"-                    (dataFromUrl "https://vega.github.io/vega-lite/data/lookup_people.csv" [])-                    "name"-                    [ "age", "height" ]+      enc = encoding+            . position X [ PName "group", PmType Ordinal ]+            . position Y [ PName "age", PmType Quantitative, PAggregate Mean ] -        enc =-            encoding-                . position X [ PName "group", PmType Ordinal ]-                . position Y [ PName "age", PmType Quantitative, PAggregate Mean ]-    in-    toVegaLite [ des, dvals [], trans [], enc [], mark Bar [] ]+  in toVegaLite [ des, groupData, trans [], enc [], mark Bar [] ]  +-- advanced14 in elm advanced8 :: VegaLite advanced8 =     let@@ -361,15 +381,15 @@         dvals =             dataFromUrl "https://vega.github.io/vega-lite/data/iris.json" +        fields = ["petalLength", "petalWidth", "sepalLength", "sepalWidth"]         trans =             transform                 . window [ ( [ WAggregateOp Count ], "index" ) ] []-                . fold [ "petalLength", "petalWidth", "sepalLength", "sepalWidth" ]+                . fold fields                 . joinAggregate [ opAs Min "value" "min", opAs Max "value" "max" ] [ WGroupBy [ "key" ] ]                 . calculateAs "(datum.value - datum.min) / (datum.max-datum.min)" "normVal"                 . calculateAs "(datum.min + datum.max) / 2" "mid" -        fields = ["petalLength", "petalWidth", "sepalLength", "sepalWidth"]         encLine =             encoding                 . position X [ PName "key", PmType Nominal ]@@ -427,6 +447,7 @@         ]  +-- advanced15 in elm advanced9 :: VegaLite advanced9 =     let@@ -446,3 +467,281 @@                 . position Y [ PName "Major_Genre", PmType Nominal ]     in     toVegaLite [ desc, dvals [], enc [], mark Bar [] ]+++-- advanced12 in elm+--+-- changed slightly to match naming used by+-- https://vega.github.io/vega-lite/docs/density.html#example-faceted-density-estimates+--+density1 :: VegaLite+density1 =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/iris.json" []++      trans = transform+              . foldAs [ "petalWidth", "petalLength", "sepalWidth", "sepalLength" ] "organ" "value"+              . density "value" [ DnBandwidth 0.3, DnGroupBy [ "organ" ] ]++      enc = encoding+            . position X [ PName "value", pQuant, PTitle "value (cm)" ]+            . position Y [ PName "density", pQuant ]+            . row [ FName "organ", fNominal ]++  in toVegaLite [ width 300, height 50, dvals, trans [], enc [], mark Area [] ]+++-- advanced13 in elm+--+density2 :: VegaLite+density2 =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/iris.json" []++      trans = transform+              . foldAs [ "petalWidth", "petalLength", "sepalWidth", "sepalLength" ] "measurement" "value"+              . density "value"+                    [ DnBandwidth 0.3+                    , DnGroupBy [ "measurement" ]+                    , DnExtent 0 8+                    , DnSteps 200+                    ]++      enc = encoding+            . position X [ PName "value", pQuant, PTitle "width/length (cm)" ]+            . position Y [ PName "density", pQuant ]+            . color [ MName "measurement", mNominal ]++  in toVegaLite [ width 400, height 100, dvals, trans [], enc [], mark Area [ MOpacity 0.5 ] ]+++-- advanced7 in elm+filter1 :: VegaLite+filter1 =+  let des = description "Filtering the top-k items"++      dvals = dataFromColumns []+              . dataColumn "student" (Strings [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V" ])+              . dataColumn "score" (Numbers [ 100, 56, 88, 65, 45, 23, 66, 67, 13, 12, 50, 78, 66, 30, 97, 75, 24, 42, 76, 78, 21, 46 ])++      trans = transform+              . window [ ( [ WOp Rank ], "rank" ) ]+                       [ WSort [ WDescending "score" ] ]+              . filter (FExpr "datum.rank <=5")++      enc = encoding+            . position X [ PName "score", pQuant ]+            . position Y+                 [ PName "student"+                 , pNominal+                 -- , PSort [ ByFieldOp "score" Mean, Descending ]+                 , PSort [ ByChannel ChX, Descending ]+                 ]++  in toVegaLite [ des, dvals [], trans [], enc [], mark Bar [] ]+++-- advanced8 in elm+filter2 :: VegaLite+filter2 =+  let des = description "Top-k items with 'others'"++      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []++      trans = transform+              . aggregate [ opAs Mean "Worldwide_Gross" "aggregateGross" ] [ "Director" ]+              . window [ ( [ WOp RowNumber ], "rank" ) ]+                       [ WSort [ WDescending "aggregateGross" ] ]+              . calculateAs "datum.rank < 10 ? datum.Director : 'All Others'" "rankedDirector"++      enc = encoding+            . position X+                    [ PName "aggregateGross"+                    , pQuant+                    , PAggregate Mean+                    , PNoTitle+                    ]+            . position Y+                    [ PName "rankedDirector"+                    , pOrdinal+                    , PSort [ ByChannel ChX, Descending ]+                    , PNoTitle+                    ]++  in toVegaLite+        [ des+        , title "Top Directors by Average Worldwide Gross" []+        , dvals+        , trans []+        , enc []+        , mark Bar []+        ]+++-- advanced10 in elm+transform1 :: VegaLite+transform1 =+  let des = description "Cumulative Frequency Distribution"++      dvals = dataFromUrl "https://gicentre.github.io/data/putneyAirQuality2018.csv"+                [ Parse [ ( "NOX", FoNumber ) ] ]++      trans = transform+              . window [ ( [ WAggregateOp Count ], "cumulativeCount" ) ]+                       [ WSort [ WAscending "NOX" ] ]++      enc = encoding+                . position X+                    [ PName "NOX"+                    , pQuant+                    , PTitle "NOX concentration (μg/㎥)"+                    ]+                . position Y [ PName "cumulativeCount", pQuant ]++      grStops = [ (0, "white"), (1, "black") ]+      orangeStops = [ (0, "orange"), (0.5, "green"), (1, "purple") ]++      -- setting these doesn't really make a difference+      grOpts = [ GrX1 0, GrX2 1, GrY1 1, GrY2 1 ]+      markOpts = [ MFillOpacity 0.5+                 , MFillGradient GrLinear grStops grOpts+                 , MStroke "orange"+                 , MStrokeWidth 2+                 , MStrokeOpacity 0.8+                 , MStrokeDash [10, 6, 6, 6]+                 , MStrokeDashOffset 5+                 , MStrokeGradient GrLinear orangeStops []+                 ]++  in toVegaLite [ des, width 500, dvals, trans [], enc [], mark Area markOpts ]+++-- advanced11 in elm+layered1 :: VegaLite+layered1 =+  let des = description "Layered Histogram and Cumulative Histogram"+      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []++      trans = transform+                . binAs [] "IMDB_Rating" "binIMDB_Rating"+                . aggregate [ opAs Count "" "count" ] [ "binIMDB_Rating", "binIMDB_Rating_end" ]+                . filter (FExpr "datum.binIMDB_Rating !== null")+                . window [ ( [ WAggregateOp Sum, WField "count" ], "cumulativeCount" ) ]+                         [ WSort [ WAscending "binIMDB_Rating" ], WFrame Nothing (Just 0) ]++      enc = encoding+                . position X+                    [ PName "binIMDB_Rating"+                    , pQuant+                    -- the SZero setting is ignored here (presumably as close to 0 anyway)+                    , PScale [ SZero False ]+                    , PTitle "IMDB Rating"+                    ]+                . position X2 [ PName "binIMDB_Rating_end" ]++      enc1 = encoding+                . position Y [ PName "cumulativeCount", pQuant ]++      enc2 = encoding+                . position Y [ PName "count", pQuant ]++  in toVegaLite+        [ des+        , dvals+        , trans []+        , enc []+        , layer+            [ asSpec [ enc1 [], mark Bar [] ]+            , asSpec [ enc2 [], mark Bar [ MColor "yellow", MOpacity 0.5 ] ]+            ]+        ]+++-- advanced16 in elm+layered2 :: VegaLite+layered2 =+  let desc = description "Plot showing average data with raw values in the background."+      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv" []++      trans = transform . filter (FExpr "datum.symbol === 'GOOG'")++      encRaw = encoding+                . position X [ PName "date", pTemporal, PTimeUnit Year ]+                . position Y [ PName "price", pQuant ]++      encAv = encoding+                . position X [ PName "date", pTemporal, PTimeUnit Year ]+                . position Y [ PName "price", PAggregate Mean, pQuant ]++      specRaw = asSpec [ encRaw [], mark Point [ MOpacity 0.3 ] ]+      specAv = asSpec [ encAv [], mark Line [] ]++  in toVegaLite [ desc, dvals, trans [], layer [ specRaw, specAv ] ]+++-- advanced17 in elm+layered3 :: VegaLite+layered3 =+  let desc = description "Plot showing a 30 day rolling average with raw values in the background."+      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/seattle-weather.csv" []++      trans = transform+                . window [ ( [ WAggregateOp Mean, WField "temp_max" ], "rollingMean" ) ]+                         [ WFrame (Just (-15)) (Just 15) ]++      encRaw = encoding+                . position X [ PName "date", PTitle "Date", pTemporal ]+                . position Y [ PName "temp_max", PTitle "Maximum temperature", pQuant ]+      encAv = encoding+                . position X [ PName "date", pTemporal ]+                . position Y [ PName "rollingMean", pQuant ]++      specRaw = asSpec [ encRaw [], mark Point [ MOpacity 0.3 ] ]+      specAv = asSpec [ encAv [], mark Line [ MColor "red", MSize 3 ] ]++  in toVegaLite [ desc, width 400, height 300, dvals, trans [], layer [ specRaw, specAv ] ]+++-- advanced18 in elm+benchmark :: VegaLite+benchmark =+  let desc = description "Line chart to show benchmarking results."++      toData :: [ Double ] -> Value+      toData = toJSON++      falconData = [ 16.81999969482422, 19.759998321533203, 16.079999923706055, 19.579999923706055, 16.420000076293945, 16.200000762939453, 16.020000457763672, 15.9399995803833, 16.280000686645508, 16.119998931884766, 16.15999984741211, 16.119998931884766, 16.139999389648438, 16.100000381469727, 16.200000762939453, 16.260000228881836, 19.35999870300293, 19.700000762939453, 15.9399995803833, 19.139999389648438, 16.200000762939453, 16.119998931884766, 19.520000457763672, 19.700000762939453, 16.200000762939453, 20.979999542236328, 16.299999237060547, 16.420000076293945, 16.81999969482422, 16.5, 16.560001373291016, 16.18000030517578, 16.079999923706055, 16.239999771118164, 16.040000915527344, 16.299999237060547, 19.399999618530273, 15.699999809265137, 16.239999771118164, 15.920000076293945, 16.259998321533203, 16.219999313354492, 16.520000457763672, 16.459999084472656, 16.360000610351563, 15.719999313354492, 16.060001373291016, 15.960000991821289, 16.479999542236328, 16.600000381469727, 16.240001678466797, 16.940000534057617, 16.220001220703125, 15.959999084472656, 15.899999618530273, 16.479999542236328, 16.31999969482422, 15.75999927520752, 15.999998092651367, 16.18000030517578, 16.219999313354492, 15.800000190734863, 16.139999389648438, 16.299999237060547, 16.360000610351563, 16.260000228881836, 15.959999084472656, 15.9399995803833, 16.53999900817871, 16.139999389648438, 16.259998321533203, 16.200000762939453, 15.899999618530273, 16.079999923706055, 16.079999923706055, 15.699999809265137, 15.660000801086426, 16.139999389648438, 23.100000381469727, 16.600000381469727, 16.420000076293945, 16.020000457763672, 15.619999885559082, 16.35999870300293, 15.719999313354492, 15.920001029968262, 15.5600004196167, 16.34000015258789, 22.82000160217285, 15.660000801086426, 15.5600004196167, 16, 16, 15.819999694824219, 16.399999618530273, 16.46000099182129, 16.059999465942383, 16.239999771118164, 15.800000190734863, 16.15999984741211, 16.360000610351563, 19.700000762939453, 16.10000228881836, 16.139999389648438, 15.819999694824219, 16.439998626708984, 16.139999389648438, 16.020000457763672, 15.860000610351563, 16.059999465942383, 16.020000457763672, 15.920000076293945, 15.819999694824219, 16.579999923706055, 15.880000114440918, 16.579999923706055, 15.699999809265137, 19.380001068115234, 19.239999771118164, 16, 15.980000495910645, 15.959999084472656, 16.200000762939453, 15.980000495910645, 16.34000015258789, 16.31999969482422, 16.260000228881836, 15.920000076293945, 15.540000915527344, 16.139999389648438, 16.459999084472656, 16.34000015258789, 15.819999694824219, 19.719999313354492, 15.75999927520752, 16.499998092651367, 15.719999313354492, 16.079999923706055, 16.439998626708984, 16.200000762939453, 15.959999084472656, 16, 16.100000381469727, 19.31999969482422, 16.100000381469727, 16.18000030517578, 15.959999084472656, 22.639999389648438, 15.899999618530273, 16.279998779296875, 16.100000381469727, 15.920000076293945, 16.079999923706055, 16.260000228881836, 15.899999618530273, 15.820001602172852, 15.699999809265137, 15.979998588562012, 16.380001068115234, 16.040000915527344, 19.420000076293945, 15.9399995803833, 16.15999984741211, 15.960000991821289, 16.259998321533203, 15.780000686645508, 15.880000114440918, 15.980000495910645, 16.060001373291016, 16.119998931884766, 23.020000457763672, 15.619999885559082, 15.920000076293945, 16.060001373291016, 14.780000686645508, 16.260000228881836, 19.520000457763672, 16.31999969482422, 16.600000381469727, 16.219999313354492, 19.740001678466797, 19.46000099182129, 15.940000534057617, 15.839999198913574, 16.100000381469727, 16.46000099182129, 16.17999839782715, 16.100000381469727, 15.9399995803833, 16.060001373291016, 15.860000610351563, 15.819999694824219, 16.03999900817871, 16.17999839782715, 15.819999694824219, 17.299999237060547, 15.9399995803833, 15.739999771118164, 15.719999313354492, 15.679998397827148, 15.619999885559082, 15.600000381469727, 16.03999900817871, 15.5, 15.600001335144043, 19.439998626708984, 15.960000991821289, 16.239999771118164, 16.040000915527344, 16.239999771118164 ]++      squareData = [ 24.200000762939453, 17.899999618530273, 15.800000190734863, 58.400001525878906, 151, 2523.10009765625, 245.3000030517578, 136, 72.30000305175781, 55.70000076293945, 42.400001525878906, 37.70000076293945, 30.100000381469727, 30.100000381469727, 21.799999237060547, 20.600000381469727, 21.799999237060547, 17.600000381469727, 18.200000762939453, 21, 941.7000122070313, 177.39999389648438, 2821.800048828125, 359.20001220703125, 318, 217.10000610351563, 126, 69, 57.79999923706055, 45.29999923706055, 35.599998474121094, 29.100000381469727, 23.799999237060547, 44.20000076293945, 17.700000762939453, 17.700000762939453, 15.699999809265137, 27.799999237060547, 22.799999237060547, 3853.60009765625, 91.5999984741211, 181.39999389648438, 476.29998779296875, 265.8999938964844, 254.60000610351563, 2583.199951171875, 124.80000305175781, 73.19999694824219, 56.400001525878906, 48.70000076293945, 41.599998474121094, 21.100000381469727, 20.299999237060547, 21.299999237060547, 18.299999237060547, 17.100000381469727, 19.5, 828.2000122070313, 162.1999969482422, 217.89999389648438, 205.5, 197.60000610351563, 2249.800048828125, 103.0999984741211, 71.69999694824219, 57.599998474121094, 41.400001525878906, 34.5, 22, 20.5, 21.700000762939453, 18.299999237060547, 17.299999237060547, 19.399999618530273, 666.7999877929688, 214.89999389648438, 212.3000030517578, 125.80000305175781, 67.69999694824219, 56.099998474121094, 45.79999923706055, 38.29999923706055, 33, 35.400001525878906, 22.700000762939453, 19.399999618530273, 19.899999618530273, 24.100000381469727, 19.299999237060547, 21.299999237060547, 3508.699951171875, 204.10000610351563, 125.4000015258789, 65.30000305175781, 60.79999923706055, 44.099998474121094, 36.29999923706055, 30.5, 28.600000381469727, 16.5, 18.600000381469727, 23.700000762939453, 22.299999237060547, 17.600000381469727, 19.200000762939453, 448.79998779296875, 124.4000015258789, 66.5999984741211, 53.5, 51, 45.20000076293945, 28.399999618530273, 29.200000762939453, 26.700000762939453, 25.899999618530273, 18.100000381469727, 17.600000381469727, 20.100000381469727, 25.200000762939453, 3332, 67.5, 53.599998474121094, 56.599998474121094, 39.900001525878906, 27.600000381469727, 29.600000381469727, 33.5, 17.200000762939453, 18.799999237060547, 25.200000762939453, 16.700000762939453, 16.899999618530273, 240.1999969482422, 52.400001525878906, 42.099998474121094, 33.900001525878906, 28, 28.600000381469727, 17.299999237060547, 20, 21, 22.799999237060547, 16.700000762939453, 19.200000762939453, 175.39999389648438, 43.5, 34.70000076293945, 29.700000762939453, 34.900001525878906, 25.799999237060547, 17.299999237060547, 22.600000381469727, 17.600000381469727, 17.200000762939453, 19.200000762939453, 111.80000305175781, 35.400001525878906, 27.600000381469727, 25.399999618530273, 21.899999618530273, 18.600000381469727, 18.100000381469727, 21.200000762939453, 17.899999618530273, 17, 80.5999984741211, 29.799999237060547, 30.100000381469727, 16, 26.799999237060547, 17.5, 22.299999237060547, 16.799999237060547, 22.399999618530273, 77.4000015258789, 31, 29.700000762939453, 28.700000762939453, 26, 16.899999618530273, 15.800000190734863, 19, 52.599998474121094, 25.200000762939453, 16.700000762939453, 17.899999618530273, 21, 19.799999237060547, 18.799999237060547, 46.5, 17.5, 16.799999237060547, 18.299999237060547, 18.299999237060547, 14.899999618530273, 41, 18.299999237060547, 17.299999237060547, 17, 17.5, 32.29999923706055, 22.600000381469727, 16.600000381469727, 17.899999618530273, 25.600000381469727, 17.5, 20.299999237060547, 25.200000762939453, 18.600000381469727, 17.700000762939453 ]++      trans = transform+              . window [ ( [ WOp RowNumber ], "row" ) ] []+              . calculateAs "1000/datum.data" "fps"++      transSquare = trans . calculateAs "'Square Crossfilter (3M)'" "system"+      transFalcon = trans . calculateAs "'Falcon'" "system"++      enc = encoding+            . position X [ PName "row"+                         , pQuant+                         , PAxis [ AxGrid False, AxTitle "Trial" ]+                         , PScale [ SNice (IsNice False) ] ]+            . position Y [ PName "fps"+                         , pQuant+                         , PAxis [ AxGrid False, AxTitle "Frames per Second (fps)" ]+                         , PScale [ SType ScLog ] ]+            . color [ MName "system"+                    , mNominal+                    , MLegend [ LOrient LOBottomRight, LTitle "System" ] ]+            . size [ MNumber 1 ]++      specFalcon = asSpec [ dataFromSource "falcon" [], transFalcon [], mark Line [] ]+      specSquare = asSpec [ dataFromSource "square" [], transSquare [], mark Line [] ]++  in toVegaLite+        [ desc+        , width 500+        , height 300+        , datasets [ ( "falcon", dataFromJson (toData falconData) [] )+                   , ( "square", dataFromJson (toData squareData) [] ) ]+        , enc []+        , layer [ specFalcon, specSquare ]+        ]
tests/Gallery/Bar.hs view
@@ -4,6 +4,8 @@ -- Based on the Elm VegaLite GalleryBar.elm (from development of version -- 1.13.0) --+-- TODO: update to add new tests from Elm (v2.0)+ module Gallery.Bar (testSpecs) where  import Graphics.Vega.VegaLite@@ -27,9 +29,28 @@             , ("bar12", bar12)             , ("bar13", bar13)             , ("bar14", bar14)+            , ("agesorted", ageSorted)+            , ("explicitbins", explicitBins)+            , ("logscaled", logScaled)+            , ("signedpopulation", signedPopulation)+            , ("labeloverlay", labelOverlay)+            , ("wilkinsondotplot", wilkinsonDotPlot)             ]  +pName :: T.Text -> PositionChannel+pName = PName++mName :: T.Text -> MarkChannel+mName = MName++pNominal, pOrdinal, pQuant :: PositionChannel+pNominal = PmType Nominal+pOrdinal = PmType Ordinal+pQuant = PmType Quantitative+++-- bar1 in GalleryBar.elm bar1 :: VegaLite bar1 =     let@@ -48,6 +69,7 @@     in     toVegaLite [ des, dvals [], mark Bar [], enc [] ] +-- bar4 in GalleryBar.elm bar2 :: VegaLite bar2 =     let@@ -67,6 +89,7 @@         ]  +-- bar2 in GalleryBar.elm (except I've added a sorting specifier to Y) bar3 :: VegaLite bar3 =     let@@ -78,18 +101,25 @@          enc =             encoding-                . position X [ PName "people", PmType Quantitative, PAggregate Sum, PAxis [ AxTitle "population" ] ]-                . position Y [ PName "age", PmType Ordinal, PScale [ SRangeStep (Just 17) ], PSort [ Descending ] ]+                . position X [ PName "people"+                             , PmType Quantitative+                             , PAggregate Sum+                             , PAxis [ AxTitle "population" ] ]+                . position Y [ PName "age"+                             , PmType Ordinal+                             , PSort [ Descending ] ]     in     toVegaLite         [ des         , dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []         , mark Bar []+        , heightStep 17         , trans []         , enc []         ]  +-- bar7 in GalleryBar.elm bar4 :: VegaLite bar4 =     let@@ -103,7 +133,7 @@          enc =             encoding-                . position X [ PName "gender", PmType Nominal, PScale [ SRangeStep (Just 12) ], PAxis [ AxNoTitle ] ]+                . position X [ PName "gender", PmType Nominal, PAxis [ AxNoTitle ] ]                 . position Y [ PName "people", PmType Quantitative, PAggregate Sum, PAxis [ AxTitle "population", AxGrid False ] ]                 . column [ FName "age", FmType Ordinal ]                 . color [ MName "gender", MmType Nominal, MScale [ SRange (RStrings [ "#EA98D2", "#659CCA" ]) ] ]@@ -117,12 +147,14 @@         [ des         , dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []         , mark Bar []+        , widthStep 12         , trans []         , enc []         , config []         ]  +-- bar8 in GalleryBar.elm bar5 :: VegaLite bar5 =     let@@ -140,7 +172,11 @@          enc =             encoding-                . position X [ PName "date", PmType Ordinal, PTimeUnit Month, PAxis [ AxTitle "Month of the year" ] ]+                . position X [ PName "date"+                             , PmType Ordinal+                             , PTimeUnit Month+                             , PAxis [ AxTitle "Month of the year" ]+                             ]                 . position Y [ PmType Quantitative, PAggregate Count ]                 . color                     [ MName "weather"@@ -157,6 +193,7 @@         ]  +-- bar9 in GalleryBar.elm bar6 :: VegaLite bar6 =     let@@ -177,6 +214,7 @@         ]  +-- bar10 in GalleryBar.elm bar7 :: VegaLite bar7 =     let@@ -190,19 +228,29 @@          enc =             encoding-                . position X [ PName "age", PmType Ordinal, PScale [ SRangeStep (Just 17) ] ]-                . position Y [ PName "people", PmType Quantitative, PAggregate Sum, PAxis [ AxTitle "Population" ], PStack StNormalize ]-                . color [ MName "gender", MmType Nominal, MScale [ SRange (RStrings [ "#EA98D2", "#659CCA" ]) ] ]+                . position X [ PName "age", PmType Ordinal ]+                . position Y [ PName "people"+                             , PmType Quantitative+                             , PAggregate Sum+                             , PAxis [ AxTitle "Population" ]+                             , PStack StNormalize+                             ]+                . color [ MName "gender"+                        , MmType Nominal+                        , MScale [ SRange (RStrings [ "#EA98D2", "#659CCA" ]) ]+                        ]     in     toVegaLite         [ des         , dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []         , trans []         , mark Bar []+        , widthStep 17         , enc []         ]  +-- bar11 in GalleryBar.elm bar8 :: VegaLite bar8 =     let@@ -224,6 +272,7 @@     toVegaLite [ des, dvals [], mark Bar [], enc [] ]  +-- bar12 in GalleryBar.elm bar9 :: VegaLite bar9 =     let@@ -244,6 +293,7 @@     toVegaLite [ des, dvals [], mark Bar [], enc [] ]  +-- bar13 in GalleryBar.elm bar10 :: VegaLite bar10 =     let@@ -257,9 +307,17 @@          enc =             encoding-                . position X [ PName "age", PmType Ordinal, PScale [ SRangeStep (Just 17) ] ]-                . position Y [ PName "people", PmType Quantitative, PAggregate Sum, PAxis [ AxTitle "Population" ], PStack NoStack ]-                . color [ MName "gender", MmType Nominal, MScale [ SRange (RStrings [ "#e377c2", "#1f77b4" ]) ] ]+                . position X [ PName "age", PmType Ordinal ]+                . position Y [ PName "people"+                             , PmType Quantitative+                             , PAggregate Sum+                             , PAxis [ AxTitle "Population" ]+                             , PStack NoStack+                             ]+                . color [ MName "gender"+                        , MmType Nominal+                        , MScale [ SRange (RStrings [ "#e377c2", "#1f77b4" ]) ]+                        ]                 . opacity [ MNumber 0.7 ]     in     toVegaLite@@ -267,10 +325,12 @@         , dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []         , trans []         , mark Bar []+        , widthStep 17         , enc []         ]  +-- bar15 in GalleryBar.elm bar11 :: VegaLite bar11 =     let@@ -309,6 +369,7 @@     toVegaLite [ des, dvals [], mark Bar [], enc [] ]  +-- bar16 in GalleryBar.elm bar12 :: VegaLite bar12 =     let@@ -329,7 +390,9 @@             asSpec [mark Bar [] ]          specText =-            asSpec [ mark Text [ MStyle [ "label" ] ], encoding (text [ TName "b", TmType Quantitative ] []) ]+            asSpec [ mark Text [ MStyle [ "label" ] ]+                   , encoding (text [ TName "b", TmType Quantitative ] [])+                   ]          config =             configure . configuration (NamedStyle "label" [ MAlign AlignLeft, MBaseline AlignMiddle, MdX 3 ])@@ -355,6 +418,7 @@     in oldRows ++ newRows  +-- bar19 in GalleryBar.elm bar13 :: VegaLite bar13 =     let@@ -416,6 +480,7 @@     toVegaLite [ des, config [], width 800, height 200, dvals [], mark Point [ MFilled True ], enc [] ]  +-- bar20 in GalleryBar.elm bar14 :: VegaLite bar14 =     let@@ -445,3 +510,216 @@                 . size [ MNumber 65 ]     in     toVegaLite [ des, config [], width 800, height 200, dvals [], trans [], mark Text [ MBaseline AlignMiddle ], enc [] ]+++-- bar3 in GalleryBar.elm, see bar3 above+ageSorted :: VegaLite+ageSorted =+  let des = description "A bar chart showing the US population distribution of age groups in 2000, sorted by population"++      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []++      trans = transform . filter (FExpr "datum.year == 2000")++      enc = encoding+            . position X [ PName "people"+                         , PmType Quantitative+                         , PAggregate Sum+                         , PAxis [ AxTitle "population" ]+                         ]+            . position Y [ PName "age"+                         , PmType Ordinal+                         , PSort [ ByChannel ChX+                                 , Descending ]+                         ]++  in toVegaLite [ des+                , heightStep 17+                , dvals+                , trans []+                , enc []+                , mark Bar []+                ]+++-- bar5 in GalleryBar.elm+explicitBins :: VegaLite+explicitBins =+  let dvals = dataFromColumns []+              . dataColumn "binStart" (Numbers [ 8, 10, 12, 14, 16, 18, 20, 22 ])+              . dataColumn "binEnd" (Numbers [ 10, 12, 14, 16, 18, 20, 22, 24 ])+              . dataColumn "count" (Numbers [ 7, 29, 71, 127, 94, 54, 17, 5 ])++      enc = encoding+            . position X [ pName "binStart"+                         , pQuant+                         , PBin [ Step 2 ] ]+            . position X2 [ pName "binEnd" ]+            . position Y [ pName "count"+                         , pQuant ]++  in toVegaLite [ dvals [], enc [], mark Bar [] ]+++-- bar6 in GalleryBar.elm+logScaled :: VegaLite+logScaled =+  let des = description "Log-scaled Histogram (may improve after https://github.com/vega/vega-lite/issues/4792)"++      dvals = dataFromColumns []+              . dataColumn "x" (Numbers [ 0.01, 0.1, 1, 1, 1, 1, 10, 10, 100, 500, 800 ])++      trans = transform+              . calculateAs "log(datum.x)/log(10)" "logX"+              . binAs [] "logX" "binLogX"+              . calculateAs "pow(10,datum.binLogX)" "x1"+              . calculateAs "pow(10,datum.binLogX_end)" "x2"++      enc = encoding+            . position X [ pName "x1"+                         , pQuant+                         , PScale [ SType ScLog, SBase 10 ]+                         , PAxis [ AxTickCount 5 ]+                         ]+            . position X2 [ pName "x2" ]+            . position Y [ PAggregate Count, pQuant ]++  in toVegaLite [ des, dvals [], trans [], enc [], mark Bar [] ]+++-- bar14 in GalleryBar.elm+signedPopulation :: VegaLite+signedPopulation =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []++      trans = transform+              . filter (FExpr "datum.year == 2000")+              . calculateAs "datum.sex == 2 ? 'Female' : 'Male'" "gender"+              . calculateAs "datum.sex == 2 ? datum.people : -datum.people" "signedPeople"++      enc = encoding+            . position Y [ pName "age"+                         , pOrdinal+                         , PAxis []+                         , PSort [ Descending ]+                         ]+            . position X [ pName "signedPeople"+                         , PAggregate Sum+                         , pQuant+                         , PAxis [ AxTitle "Population", AxFormat "s" ]+                         ]+            . color [ mName "gender"+                    , MmType Nominal+                    , MScale [ SRange (RStrings [ "#675193", "#ca8861" ]) ]+                    , MLegend [ LOrient LOTop, LTitle "" ]+                    ]++      cfg = configure+            . configuration (View [ ViewStroke Nothing ])+            . configuration (Axis [ Grid False ])++  in toVegaLite [ width 300+                , height 200+                , cfg []+                , dvals+                , trans []+                , enc []+                , mark Bar [] ]+++-- bar17 in GalleryBar.elm+labelOverlay :: VegaLite+labelOverlay =+  let des = description "Bar chart with label overlay"++      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []++      trans = transform+              . calculateAs "isValid(datum.Major_Genre)? datum.Major_Genre : 'unclassified'" "genre"++      enc = encoding+            . position Y+                    [ pName "genre"+                    , pNominal+                    , PSort+                        [ CustomSort+                            (Strings+                                [ "Action"+                                , "Adventure"+                                , "Comedy"+                                , "Black Comedy"+                                , "Romantic Comedy"+                                , "Concert/Performance"+                                , "Documentary"+                                , "Drama"+                                , "Horror"+                                , "Musical"+                                , "Thriller/Suspense"+                                , "Western"+                                , "unclassified"+                                ]+                            )+                        ]+                    , PAxis []+                    ]++      encBar = encoding+               . position X+                    [ pName "IMDB_Rating"+                    , PAggregate Mean+                    , pQuant+                    , PScale [ SDomain (DNumbers [ 0, 10 ]) ]+                    , PTitle "Mean IMDB Ratings"+                    ]++      specBar =asSpec [ encBar [], mark Bar [ MColor "#ddd" ] ]++      encText = encoding+                . text [ TName "genre", TmType Nominal ]+                . detail [ DAggregate Count, DmType Quantitative ]++      specText = asSpec [ encText [], mark Text [ MAlign AlignCenter, MdX 5 ] ]++  in toVegaLite+        [ des+        , width 200+        , heightStep 16+        , dvals+        , trans []+        , enc []+        , layer [ specBar, specText ]+        ]+++-- bar18 in GalleryBar.elm+wilkinsonDotPlot :: VegaLite+wilkinsonDotPlot =+  let desc = description "A Wilkinson dot plot"++      cfg = configure+            . configuration (View [ ViewStroke Nothing ])++      dvals = dataFromColumns []+              . dataColumn "data" (Numbers [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 ])++      trans = transform+              . window [ ( [ WOp Rank, WField "rank" ], "id" ) ] [ WGroupBy [ "data" ] ]++      enc = encoding+            . position X [ pName "data", pOrdinal ]+            . position Y+                    [ pName "id"+                    , pOrdinal+                    , PAxis []+                    , PSort [ Descending ]+                    ]++  in toVegaLite+        [ desc+        , cfg []+        , height 100+        , dvals []+        , trans []+        , enc []+        , mark Circle [ MOpacity 1 ]+        ]
tests/Gallery/Dist.hs view
@@ -18,6 +18,7 @@             , ("dist3", dist3)             , ("dist4", dist4)             , ("dist5", dist5)+            , ("quantile1", quantile1)             ]  @@ -241,3 +242,22 @@         , encAge []         , layer [ specLWhisker, specUWhisker, specBox, specBoxMid ]         ]+++quantile1 :: VegaLite+quantile1 =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/normal-2d.json" []++      trans = transform+              . quantile "u" [ QtStep 0.01, QtAs "p" "v" ]+              . calculateAs "quantileUniform(datum.p)" "unif"+              . calculateAs "quantileNormal(datum.p)" "norm"++      enc x y = encoding+                . position X [ PName x, PmType Quantitative ]+                . position Y [ PName y, PmType Quantitative ]++      leftSpec = asSpec [ mark Point [], enc "unif" "v" [] ]+      rightSpec = asSpec [ mark Point [], enc "norm" "v" [] ]++  in toVegaLite [ dvals, trans [], hConcat [ leftSpec, rightSpec ] ]
tests/Gallery/Facet.hs view
@@ -39,12 +39,12 @@          enc =             encoding-                . position X [ PName "age", PmType Ordinal, PScale [ SRangeStep (Just 17) ] ]+                . position X [ PName "age", PmType Ordinal ]                 . position Y [ PName "people", PmType Quantitative, PAggregate Sum, PAxis [ AxTitle "Population" ] ]                 . color [ MName "gender", MmType Nominal, MScale [ SRange (RStrings [ "#EA98D2", "#659CCA" ]) ] ]                 . row [ FName "gender", FmType Nominal ]     in-    toVegaLite [ des, dvals [], trans [], mark Bar [], enc [] ]+    toVegaLite [ des, dvals [], trans [], mark Bar [], widthStep 17, enc [] ]   facet2 :: VegaLite@@ -92,13 +92,16 @@ facet4 =     let         des =-            description "Disitributions of car engine power for different countries of origin"+            description "Distributions of car engine power for different countries of origin"          enc =             encoding                 . position X [ PName "Horsepower", PmType Quantitative, PBin [ MaxBins 15 ] ]                 . position Y [ PmType Quantitative, PAggregate Count ]-                . row [ FName "Origin", FmType Ordinal ]+                . row [ FName "Origin"+                      , FmType Ordinal+                      , FTitle "Origin facet"+                      ]     in     toVegaLite         [ des@@ -144,7 +147,6 @@                 . position Y                     [ PName "variety"                     , PmType Ordinal-                    , PScale [ SRangeStep (Just 12) ]                     , PSort [ ByChannel ChX, Descending ]                     ]                 . color [ MName "year", MmType Nominal ]@@ -159,7 +161,7 @@             , FSort [ ByFieldOp "yield" Median ]             , FHeader [ HNoTitle ]             ]-        , specification (asSpec [ enc [], mark Point [] ])+        , specification (asSpec [ enc [], heightStep 12, mark Point [] ])         ]  @@ -192,7 +194,12 @@                 . row                     [ FName "symbol"                     , FmType Nominal-                    , FHeader [ HTitle "Stock price", HLabelAngle 0 ]+                    , FHeader [ HTitle "Stock price"+                              , HLabelAngle 0+                              -- I don't know why the labels only align+                              -- when AlignLeft is used.+                              , HLabelAlign AlignLeft+                              ]                     ]          res =
tests/Gallery/Geo.hs view
@@ -27,7 +27,7 @@  {-| No borders around maps -}-cfg :: [LabelledSpec] -> ( VLProperty, VLSpec )+cfg :: [ConfigureSpec] -> PropertySpec cfg =     configure         . configuration (View [ ViewStroke Nothing ])@@ -35,28 +35,26 @@  geo1 :: VegaLite geo1 =-    let-        countyData =-            dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json"-                [ TopojsonFeature "counties" ]+  let countyData =+        dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json"+        [ TopojsonFeature "counties" ] -        unemploymentData =-            dataFromUrl "https://vega.github.io/vega-lite/data/unemployment.tsv" []+      unemploymentData =+        dataFromUrl "https://vega.github.io/vega-lite/data/unemployment.tsv" [] -        trans =-            transform-                . lookup "id" unemploymentData "id" [ "rate" ]+      trans =+        transform+        . lookup "id" unemploymentData "id" (LuFields [ "rate" ]) -        proj =-            projection [ PrType AlbersUsa ]+      proj = projection [ PrType AlbersUsa ] -        enc =-            encoding-                . color [ MName "rate", MmType Quantitative, MSort [ Descending ] ]-    in-    toVegaLite [ cfg [], width 500, height 300, countyData, proj, trans [], enc [], mark Geoshape [] ]+      enc = encoding+            . color [ MName "rate", MmType Quantitative, MSort [ Descending ] ] +  in toVegaLite [ cfg [], width 500, height 300, countyData+                , proj, trans [], enc [], mark Geoshape [] ] + geo2 :: VegaLite geo2 =     let@@ -119,54 +117,52 @@  geo4 :: VegaLite geo4 =-    let-        backdropSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]-                , mark Geoshape []-                , encoding (color [ MString "#eee" ] [])-                ]+  let backdropSpec =+        asSpec+        [ dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]+        , mark Geoshape []+        , encoding (color [ MString "#eee" ] [])+        ] -        airportsEnc =-            encoding-                . position Longitude [ PName "longitude", PmType Quantitative ]-                . position Latitude [ PName "latitude", PmType Quantitative ]-                . size [ MNumber 5 ]-                . color [ MString "gray" ]+      airportsEnc =+        encoding+        . position Longitude [ PName "longitude", PmType Quantitative ]+        . position Latitude [ PName "latitude", PmType Quantitative ]+        . size [ MNumber 5 ]+        . color [ MString "gray" ] -        airportsSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" []-                , mark Circle []-                , airportsEnc []-                ]+      airportData =+        dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" []+        +      airportsSpec =+        asSpec+        [ airportData+        , mark Circle []+        , airportsEnc []+        ] -        trans =-            transform-                . filter (FEqual "origin" (Str "SEA"))-                . lookup "origin" (dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" []) "iata" [ "latitude", "longitude" ]-                . calculateAs "datum.latitude" "origin_latitude"-                . calculateAs "datum.longitude" "origin_longitude"-                . lookup "destination" (dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" []) "iata" [ "latitude", "longitude" ]-                . calculateAs "datum.latitude" "dest_latitude"-                . calculateAs "datum.longitude" "dest_longitude"+      trans =+        transform+        . filter (FEqual "origin" (Str "SEA"))+        . lookup "origin" airportData "iata" (LuAs "o")+        . lookup "destination" airportData "iata" (LuAs "d") -        flightsEnc =-            encoding-                . position Longitude [ PName "origin_longitude", PmType Quantitative ]-                . position Latitude [ PName "origin_latitude", PmType Quantitative ]-                . position Longitude2 [ PName "dest_longitude" ]-                . position Latitude2 [ PName "dest_latitude" ]+      flightsEnc = +        encoding+        . position Longitude [ PName "o.longitude", PmType Quantitative ]+        . position Latitude [ PName "o.latitude", PmType Quantitative ]+        . position Longitude2 [ PName "d.longitude" ]+        . position Latitude2 [ PName "d.latitude" ] -        flightsSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/flights-airport.csv" []-                , trans []-                , mark Rule []-                , flightsEnc []-                ]-    in-    toVegaLite+      flightsSpec =+        asSpec+        [ dataFromUrl "https://vega.github.io/vega-lite/data/flights-airport.csv" []+        , trans []+        , mark Rule []+        , flightsEnc []+        ]++  in toVegaLite         [ cfg []         , description "Rules (line segments) connecting SEA to every airport reachable via direct flight"         , width 800@@ -184,12 +180,16 @@                 . shape [ MName "geo", MmType GeoFeature ]                 . color [ MRepeat Row, MmType Quantitative, MSort [ Descending ] ] +        statesData =+          dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json"+                      [ TopojsonFeature "states" ]+         spec =             asSpec                 [ width 500                 , height 300                 , dataFromUrl "https://vega.github.io/vega-lite/data/population_engineers_hurricanes.csv" []-                , transform (lookupAs "id" (dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]) "id" "geo" [])+                , transform (lookup "id" statesData "id" (LuAs "geo") [])                 , projection [ PrType AlbersUsa ]                 , mark Geoshape []                 , enc []@@ -242,52 +242,55 @@  geo7 :: VegaLite geo7 =-    let-        backdropSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]-                , mark Geoshape []-                , encoding (color [ MString "#eee" ] [])-                ]+  let backdropSpec =+        asSpec+        [ dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]+        , mark Geoshape []+        , encoding (color [ MString "#eee" ] [])+        ] -        airportsEnc =-            encoding-                . position Longitude [ PName "longitude", PmType Quantitative ]-                . position Latitude [ PName "latitude", PmType Quantitative ]-                . size [ MNumber 5 ]-                . color [ MString "gray" ]+      airportsEnc =+        encoding+        . position Longitude [ PName "longitude", PmType Quantitative ]+        . position Latitude [ PName "latitude", PmType Quantitative ]+        . size [ MNumber 5 ]+        . color [ MString "gray" ] -        airportsSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" []-                , mark Circle []-                , airportsEnc []-                ]+      airportData =+        dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" [] -        itinerary =-            dataFromColumns []-                . dataColumn "airport" (Strings [ "SEA", "SFO", "LAX", "LAS", "DFW", "DEN", "ORD", "JFK", "ATL" ])-                . dataColumn "order" (Numbers [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ])+      airportsSpec =+        asSpec+        [ airportData+        , mark Circle []+        , airportsEnc []+        ] -        trans =-            transform-                . lookup "airport" (dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" []) "iata" [ "latitude", "longitude" ]+      itinerary =+        dataFromColumns []+        . dataColumn "airport" (Strings [ "SEA", "SFO", "LAX", "LAS", "DFW", "DEN", "ORD", "JFK", "ATL" ])+        . dataColumn "order" (Numbers [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]) -        flightsEnc =-            encoding-                . position Longitude [ PName "longitude", PmType Quantitative ]-                . position Latitude [ PName "latitude", PmType Quantitative ]-                . order [ OName "order", OmType Ordinal ]+      trans =+        transform+        . lookup "airport" airportData "iata"+            (LuFields [ "latitude", "longitude" ]) -        flightsSpec =-            asSpec-                [ itinerary []-                , trans []-                , mark Line []-                , flightsEnc []-                ]-    in-    toVegaLite+      flightsEnc =+        encoding+        . position Longitude [ PName "longitude", PmType Quantitative ]+        . position Latitude [ PName "latitude", PmType Quantitative ]+        . order [ OName "order", OmType Ordinal ]++      flightsSpec =+        asSpec+        [ itinerary []+        , trans []+        , mark Line []+        , flightsEnc []+        ]++  in toVegaLite         [ cfg []         , description "Line drawn between airports in the U.S. simulating a flight itinerary"         , width 800@@ -299,7 +302,9 @@  geo8 :: VegaLite geo8 =-    let+    let geoData =+          dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]+         enc =             encoding                 . shape [ MName "geo", MmType GeoFeature ]@@ -312,7 +317,7 @@         , width 500         , height 300         , dataFromUrl "https://vega.github.io/vega-lite/data/income.json" []-        , transform (lookupAs "id" (dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]) "id" "geo" [])+        , transform (lookup "id" geoData "id" (LuAs "geo") [])         , projection [ PrType AlbersUsa ]         , mark Geoshape []         , enc []
tests/Gallery/Interaction.hs view
@@ -446,7 +446,7 @@ -- initInterval :: Maybe (DataValue, DataValue) -> Maybe (DataValue, DataValue) -> VegaLite initInterval mx my =-  let desc = "Drag out a rectangular brush to hughlight points."+  let desc = "Drag out a rectangular brush to highlight points."        sel = selection               . select "brush" Interval [ SInitInterval mx my ]@@ -462,7 +462,7 @@    in toVegaLite      [ description desc-     , dataFromUrl "data/cars.json" []+     , dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []      , mark Point []      , enc []      , sel []@@ -473,8 +473,9 @@ xInit = (Number 55, Number 160) yInit = (Number 13, Number 37) --- Note: interaction11a is invalid according to the Vega Lite 3.4.0---       specification.+-- Note: the Vega-Lite spec (circa version 4) does not support the+--       "Nothing Nothing" case - aka interaction11a - so this is a+--       check to make sure we handle this case correctly. -- interaction11a, interaction11b, interaction11c, interaction11d :: VegaLite interaction11a = initInterval Nothing Nothing
tests/Gallery/Line.hs view
@@ -4,6 +4,8 @@ -- Based on the Elm VegaLite GalleryLine.elm (from development of version -- 1.13.0) --+-- TODO: update to v2.0 Elm test suite+ module Gallery.Line (testSpecs) where  import Graphics.Vega.VegaLite@@ -101,7 +103,7 @@          enc =             encoding-                . position X [ PName "year", PmType Ordinal, PScale [ SRangeStep (Just 50), SPadding 0.5 ] ]+                . position X [ PName "year", PmType Ordinal, PScale [ SPadding 0.5 ] ]                 . position Y [ PName "yield", PmType Quantitative, PAggregate Median ]                 . color [ MName "site", MmType Nominal ]     in@@ -109,6 +111,7 @@         [ des         , dataFromUrl "https://vega.github.io/vega-lite/data/barley.json" []         , mark Line []+        , widthStep 50         , enc []         ] 
tests/Gallery/Multi.hs view
@@ -18,6 +18,7 @@             , ("multi5", multi5)             , ("multi6", multi6)             , ("multi7", multi7)+            , ("multi8", multi8)             ]  @@ -383,81 +384,72 @@  multi7 :: VegaLite multi7 =-    let-        des =-            description "One dot per airport in the US overlayed on geoshape"+  let des = description "One dot per airport in the US overlayed on geoshape" -        cfg =-            configure-                . configuration (View [ ViewStroke Nothing ])+      cfg = configure+            . configuration (View [ ViewStroke Nothing ]) -        backdropSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]-                , mark Geoshape [ MFill "#ddd", MStroke "#fff" ]-                ]+      backdropSpec =+        asSpec+        [ dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "states" ]+        , mark Geoshape [ MFill "#ddd", MStroke "#fff" ]+        ] -        lineTrans =-            transform-                . filter (FSelection "mySelection")-                . lookup "origin"-                    (dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" [])-                    "iata"-                    [ "latitude", "longitude" ]-                . calculateAs "datum.latitude" "oLat"-                . calculateAs "datum.longitude" "oLon"-                . lookup "destination"-                    (dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" [])-                    "iata"-                    [ "latitude", "longitude" ]-                . calculateAs "datum.latitude" "dLat"-                . calculateAs "datum.longitude" "dLon"+      airportData =+        dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" []+      flightData =+        dataFromUrl "https://vega.github.io/vega-lite/data/flights-airport.csv" [] -        lineEnc =-            encoding-                . position Longitude [ PName "oLon", PmType Quantitative ]-                . position Latitude [ PName "oLat", PmType Quantitative ]-                . position Longitude2 [ PName "dLon" ]-                . position Latitude2 [ PName "dLat" ]+      lineTrans =+        transform+        . filter (FSelection "mySelection")+        . lookup "origin" airportData "iata" (LuAs "o")+        . lookup "destination" airportData "iata" (LuAs "d") -        lineSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/flights-airport.csv" []-                , lineTrans []-                , lineEnc []-                , mark Rule [ MColor "black", MOpacity 0.35 ]-                ]+      lineEnc =+        encoding+        . position Longitude [ PName "o.longitude", PmType Quantitative ]+        . position Latitude [ PName "o.latitude", PmType Quantitative ]+        . position Longitude2 [ PName "d.longitude" ]+        . position Latitude2 [ PName "d.latitude" ] -        airportTrans =-            transform-                . aggregate [ opAs Count "" "routes" ] [ "origin" ]-                . lookup "origin"-                    (dataFromUrl "https://vega.github.io/vega-lite/data/airports.csv" [])-                    "iata"-                    [ "state", "latitude", "longitude" ]-                . filter (FExpr "datum.state !== 'PR' && datum.state !== 'VI'")+      lineSpec =+        asSpec+        [ flightData+        , lineTrans []+        , lineEnc []+        , mark Rule [ MColor "black", MOpacity 0.35 ]+        ] -        airportEnc =-            encoding-                . position Longitude [ PName "longitude", PmType Quantitative ]-                . position Latitude [ PName "latitude", PmType Quantitative ]-                . size [ MName "routes", MmType Quantitative, MScale [ SRange (RNumbers [ 0, 1000 ]) ], MLegend [] ]-                . order [ OName "routes", OmType Quantitative, OSort [ Descending ] ]+      airportTrans =+        transform+        . aggregate [ opAs Count "" "routes" ] [ "origin" ]+        . lookup "origin" airportData "iata"+              (LuFields [ "name", "state", "latitude", "longitude" ])+        . filter (FExpr "datum.state !== 'PR' && datum.state !== 'VI'") -        sel =-            selection-                . select "mySelection" Single [ On "mouseover", Nearest True, Empty, Fields [ "origin" ] ]+      airportEnc =+        encoding+        . position Longitude [ PName "longitude", PmType Quantitative ]+        . position Latitude [ PName "latitude", PmType Quantitative ]+        . size [ MName "routes", MmType Quantitative, MScale [ SRange (RNumbers [ 0, 1000 ]) ], MLegend [] ]+        . order [ OName "routes", OmType Quantitative, OSort [ Descending ] ]+        . tooltip [ TName "name", TmType Nominal ] -        airportSpec =-            asSpec-                [ dataFromUrl "https://vega.github.io/vega-lite/data/flights-airport.csv" []-                , airportTrans []-                , sel []-                , mark Circle []-                , airportEnc []-                ]-    in-    toVegaLite+      sel =+        selection+        . select "mySelection" Single [ On "mouseover", Nearest True, Empty, Fields [ "origin" ] ]++      airportSpec =+        asSpec+        [ flightData+        , airportTrans []+        , sel []+        , mark Circle []+        , airportEnc []+        ]++  in toVegaLite         [ des         , cfg []         , width 900@@ -465,3 +457,34 @@         , projection [ PrType AlbersUsa ]         , layer [ backdropSpec, lineSpec, airportSpec ]         ]+++multi8 :: VegaLite+multi8 =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/flights-5k.json"+              [ Parse [ ( "date", FoDate "" ) ] ]++      trans = transform+              . calculateAs "hours(datum.date) + minutes(datum.date) / 60" "time"+      sel = selection+            . select "brush" Interval [ Encodings [ ChX ]+                                      , SInitInterval+                                        (Just (Number 6, Number 12))+                                        Nothing+                                      ]++      enc1 = encoding+             . position X [ PName "time"+                          , PBin [ MaxBins 30 ]+                          , PmType Quantitative ]+             . position Y [ PAggregate Count, PmType Quantitative ]+      spec1 = asSpec [ width 963, height 100, sel [], enc1 [], mark Bar [] ]++      enc2 = encoding+             . position X [ PName "time"+                          , PBin [ MaxBins 30, SelectionExtent "brush" ]+                          , PmType Quantitative ]+             . position Y [ PAggregate Count, PmType Quantitative ]+      spec2 = asSpec [ width 963, height 100, enc2 [], mark Bar [] ]++  in toVegaLite [ dvals, trans [], vConcat [ spec1, spec2 ] ]
tests/Gallery/Scatter.hs view
@@ -22,9 +22,15 @@             , ("scatter9", scatter9)             , ("scatter10", scatter10)             , ("scatter11", scatter11)+            , ("smoothing1", smoothing1)+            , ("smoothing2", smoothing2)             ]  +pQuant :: PositionChannel+pQuant = PmType Quantitative++ scatter1 :: VegaLite scatter1 =     let@@ -150,7 +156,7 @@          config =             configure-                . configuration (RemoveInvalid False)+                . configuration (MarkStyle [ MRemoveInvalid False ])          enc =             encoding@@ -277,3 +283,67 @@         , mark Text []         , enc []         ]+++-- combines scatter12 and scatter13 from elm+--+-- TODO: how to add a legend to indicate which line is which?+--+smoothing1 :: VegaLite+smoothing1 =+  let desc = description "How can we 'smooth' data?"+      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []++      ltrans = transform+              . loess "IMDB_Rating" "Rotten_Tomatoes_Rating" [ LsBandwidth 0.1 ]++      rtrans = transform+              . regression "IMDB_Rating" "Rotten_Tomatoes_Rating"+                           [ RgMethod RgPoly, RgOrder 3, RgExtent 10 90 ]++      enc = encoding+            . position X [ PName "Rotten_Tomatoes_Rating", pQuant ]+            . position Y [ PName "IMDB_Rating", pQuant ]++      pointSpec = asSpec [ mark Point [ MFilled True, MOpacity 0.3 ] ]+      trendSpec = asSpec [ ltrans [], mark Line [ MColor "firebrick" ] ]+      regSpec = asSpec [ rtrans [], mark Line [ MColor "orange" ] ]++      layers = layer [ pointSpec, trendSpec, regSpec ]++  in toVegaLite [ desc, width 300, height 300, dvals, enc [], layers ]+++-- smoothing1 but rename the columns in the transform+-- and use the default regression values+--+smoothing2 :: VegaLite+smoothing2 =+  let desc = description "How can we 'smooth' and rename data?"+      dvals = dataFromUrl "https://vega.github.io/vega-lite/data/movies.json" []++      ltrans = transform+              . loess "IMDB_Rating" "Rotten_Tomatoes_Rating"+                      [ LsAs "Rotten_Tomatoes_Rating" "ly" ]++      rtrans = transform+              . regression "IMDB_Rating" "Rotten_Tomatoes_Rating"+                           [ RgAs "Rotten_Tomatoes_Rating" "ry" ]++      enc y = encoding+              . position X [ PName "Rotten_Tomatoes_Rating", pQuant ]+              . position Y [ PName y, pQuant ]++      pointSpec = asSpec [ enc "IMDB_Rating" []+                         , mark Point [ MFilled True, MOpacity 0.3 ]+                         ]+      trendSpec = asSpec [ enc "ly" []+                         , ltrans []+                         , mark Line [ MColor "firebrick" ] ]+      regSpec = asSpec [ enc "ry" []+                       , rtrans []+                       , mark Line [ MColor "orange" ] ]++      layers = layer [ pointSpec, trendSpec, regSpec ]++  in toVegaLite [ desc, width 300, height 300, dvals, layers ]
tests/Gallery/Table.hs view
@@ -49,8 +49,7 @@          conf =             configure-                . configuration (View [ ViewStrokeWidth 0 ])-                . configuration (Scale [ SCRangeStep (Just 13) ])+                . configuration (View [ ViewStrokeWidth 0, ViewStep 13 ])                 . configuration (Axis [ Domain False ])          enc =
tests/GeoTests.hs view
@@ -66,7 +66,8 @@ defaultSize2 =     toVegaLite         [ description "Default map size with view width and height specified in config."-        , configure $ configuration (View [ ViewWidth 500, ViewHeight 300 ]) []+        , configure $ configuration (View [ ViewContinuousWidth 500+                                          , ViewContinuousHeight 300 ]) []         , projection [ PrType AlbersUsa ]         , dataFromUrl "https://vega.github.io/vega-lite/data/us-10m.json" [ TopojsonFeature "counties" ]         , mark Geoshape []
+ tests/ImageTests.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++--+-- Based on the Elm VegaLite ImageTests.elm as of version 2.0+--+module ImageTests (testSpecs) where++-- import qualified Data.Aeson as A+import qualified Data.Text as T++-- import Data.Aeson ((.=))+-- import Data.Function ((&))++#if !(MIN_VERSION_base(4, 12, 0))+import Data.Monoid ((<>))+#endif++import Graphics.Vega.VegaLite++import Prelude hiding (filter)++testSpecs :: [(String, VegaLite)]+testSpecs = [ ("image1", image1)+            , ("image2", image2)+            , ("image3", image3)+            , ("image4", image4)+            , ("image5", image5)+            , ("image6", image6)+            , ("image7", image7)+            , ("image8", image8)+            , ("image9", image9)+            , ("image10", image10)+            {-+            , ("image11", image11)+            , ("image12", image12)+            -}+            ]+++base :: T.Text+base = "https://vega.github.io/vega-lite/data/"+++imgUrls :: DataValues+imgUrls = Strings (map (base <>) [ "ffox.png", "gimp.png", "7zip.png" ])++                      +imageEnc :: ([DataColumn] -> [DataColumn]) -> (BuildEncodingSpecs) -> VegaLite+imageEnc dataSupp encSupp =+  let axVals = Numbers [ 0.5, 1.5, 2.5 ]+      dvals = dataFromColumns []+              . dataColumn "x" axVals+              . dataColumn "y" axVals+              . dataSupp++      enc = encoding+            . position X [ PName "x", PmType Quantitative ]+            . position Y [ PName "y", PmType Quantitative ]+            . encSupp++  in toVegaLite [ dvals [], enc [], mark Image [ MWidth 25, MHeight 25 ] ]+++image1 :: VegaLite+image1 = imageEnc (const []) (url [ HString (base <> "ffox.png") ])+++image2 :: VegaLite+image2 =+  imageEnc+    (dataColumn "img" imgUrls)+    (url [ HName "img", HmType Nominal ])+++lakeImage :: [MarkProperty] -> VegaLite+lakeImage mProps =+  let col lbl = dataColumn lbl (Numbers [ 5 ])+      dvals = dataFromColumns [] . col "x" . col "y"++      pos t l = position t [ PName l+                           , PmType Quantitative+                           , PScale [ SDomain (DNumbers [0, 10]) ]+                           ]+      enc = encoding . pos X "x" . pos Y "y"+      encImage = enc . url [ HString "https://gicentre.github.io/data/images/LillyTarn.jpg" ]+      +  in toVegaLite+        [ dvals []+        , layer+            [ asSpec [ encImage [], mark Image mProps ]+            , asSpec [ enc [], mark Circle [ MColor "red", MSize 100, MOpacity 0.5 ] ]+            ]+        ]+++image3 :: VegaLite+image3 = lakeImage [ MWidth 100, MAspect True ]+++image4 :: VegaLite+image4 =+    lakeImage [ MWidth 100, MHeight 100, MAspect False ]+++image5 :: VegaLite+image5 =+    lakeImage [ MWidth 100, MHeight 61, MAlign AlignLeft ]+++image6 :: VegaLite+image6 =+    lakeImage [ MWidth 100, MHeight 61, MAlign AlignCenter ]+++image7 :: VegaLite+image7 =+    lakeImage [ MWidth 100, MHeight 61, MAlign AlignRight ]+++image8 :: VegaLite+image8 =+    lakeImage [ MWidth 100, MHeight 61, MBaseline AlignTop ]+++image9 :: VegaLite+image9 =+    lakeImage [ MWidth 100, MHeight 61, MBaseline AlignMiddle ]+++image10 :: VegaLite+image10 =+    lakeImage [ MWidth 100, MHeight 61, MBaseline AlignBottom ]+++{-++These two are valid according to the 4.0.2 schema, but when viewed in+the Vega Editor a warning message is displayed about how the size+channel is incompatible with the image mark and so is dropped.++image11 :: VegaLite+image11 =+  imageEnc+    (dataColumn "img" imgUrls . dataColumn "mag" (Numbers [ 1, 1, 1 ]))+    (url [ HName "img", HmType Nominal ] . size [ MName "mag", MmType Quantitative ])+++image12 :: VegaLite+image12 =+  imageEnc+    (dataColumn "img" imgUrls . dataColumn "mag" (Numbers [ 1, 2, 1 ]))+    (url [ HName "img", HmType Nominal ] . size [ MName "mag", MmType Quantitative ])++-}
tests/InteractionTests.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE OverloadedStrings #-}  ----- Based on the Elm VegaLite GeoTests.elm as of version 1.12.0+-- Based on the Elm VegaLite InteractionTests.elm as of version 1.12.0+-- Note that the numbering / naming has diverged from Elm over+-- time (I want to keep the old tests the same name) -- module InteractionTests (testSpecs) where @@ -19,6 +21,14 @@             , ("interaction6", interaction6)             , ("interaction7", interaction7)             , ("interaction8", interaction8)+            , ("initinterval", initInterval)+            , ("initintervalxy", initIntervalXY)+            , ("initintervaly", initIntervalY)+            , ("initintervalx", initIntervalX)+            , ("bindlegend", bindLegend)+            , ("bindlegend2", bindLegendDouble)+            , ("bindlegendboth", bindLegendBoth)+            , ("lookupSelection1", lookupSelection1)             ]  @@ -38,11 +48,11 @@         ]  -month, crimes :: BuildLabelledSpecs+month, crimes :: BuildEncodingSpecs month = position X [ PName "month", PmType Temporal, PNoTitle ] crimes = position Y [ PName "reportedCrimes", PmType Quantitative, PTitle "Reported crimes" ] -enc, encHighlight :: [LabelledSpec] -> PropertySpec+enc, encHighlight :: [EncodingSpec] -> PropertySpec enc =     encoding         . month@@ -65,69 +75,55 @@                 [ MNumber 0.1 ]             ] ++iPlot :: ([SelectSpec] -> PropertySpec) -> Mark -> VegaLite+iPlot sel markType =+  toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark markType [] ]++ interaction1 :: VegaLite interaction1 =-    let-        sel =-            selection . select "mySelection" Single []-    in-    toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark Line [] ]+    let sel = selection . select "mySelection" Single []+    in iPlot sel Line   interaction2 :: VegaLite interaction2 =-    let-        sel =-            selection . select "mySelection" Multi []-    in-    toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark Line [] ]+    let sel = selection . select "mySelection" Multi []+    in iPlot sel Line   interaction3 :: VegaLite interaction3 =-    let-        sel =-            selection+    let sel = selection                 . select "mySelection" Single [ Nearest True, Fields [ "crimeType" ] ]-    in-    toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark Circle [] ]+    in iPlot sel Circle   interaction4 :: VegaLite interaction4 =-    let-        sel =-            selection+    let sel = selection                 . select "mySelection" Interval [ Empty, Encodings [ ChX ] ]-    in-    toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark Circle [] ]+    in iPlot sel Circle   interaction5 :: VegaLite interaction5 =-    let-        sel =-            selection+    let sel = selection                 . select "mySelection" Interval [ BindScales, Encodings [ ChX ] ]-    in-    toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark Circle [] ]+    in iPlot sel Circle   interaction6 :: VegaLite interaction6 =-    let-        sel =-            selection+    let sel = selection                 . select "mySelection" Interval [ BindScales ]-    in-    toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark Circle [] ]+    in iPlot sel Circle   interaction7 :: VegaLite interaction7 =-    let-        sel =-            selection+    let sel = selection                 . select "mySelection"                     Single                     [ Fields [ "crimeType" ]@@ -145,15 +141,13 @@                             ]                         ]                     ]-    in-    toVegaLite [ width 540, crimeData, sel [], encHighlight [], mark Circle [] ] +    in iPlot sel Circle + interaction8 :: VegaLite interaction8 =-    let-        sel =-            selection+    let sel = selection                 . select "maxSlider"                     Single                     [ SInit [ ( "maxReported", Number 14000 ) ]@@ -165,8 +159,155 @@                     , Bind [ IRange "minReported" [ InName "Min", InMax 12800 ] ]                     ] -        trans =-            transform+        trans = transform                 . filter (FExpr "datum.reportedCrimes >= minSlider_minReported && maxSlider_maxReported >= datum.reportedCrimes")-    in-    toVegaLite [ width 540, crimeData, trans [], sel [], enc [], mark Circle [] ]++    in toVegaLite [ width 540, crimeData, trans [], sel [], enc [], mark Circle [] ]+++-- Note that an interval of Nothing Nothing can not be encoded in Vega-Lite 4.0.2,+-- so this is a check we don't create invalid output.+--+initInterval :: VegaLite+initInterval =+  let sel = selection+              . select "mySelection"+                  Interval+                  [ SInitInterval Nothing Nothing ]++  in iPlot sel Circle+++initIntervalXY :: VegaLite+initIntervalXY =+  let sel = selection+              . select "mySelection"+                  Interval+                  [ SInitInterval+                    (Just ( DateTime [ DTYear 2013 ], DateTime [ DTYear 2015 ] ))+                    (Just ( Number 4000, Number 8000 ))+                  ]++  in iPlot sel Circle+++initIntervalY :: VegaLite+initIntervalY =+  let sel = selection+              . select "mySelection"+                  Interval+                  [ SInitInterval+                    Nothing+                    (Just ( Number 4000, Number 8000 ))+                  ]++  in iPlot sel Circle+++initIntervalX :: VegaLite+initIntervalX =+  let sel = selection+              . select "mySelection"+                  Interval+                  [ Encodings [ ChX ]+                  , SInitInterval+                    (Just ( DateTime [ DTYear 2013 ], DateTime [ DTYear 2015 ] ))+                    Nothing+                  ]++  in iPlot sel Circle+++bindLegend :: VegaLite+bindLegend =+  let sel = selection+             . select "mySelection" Single [ BindLegend (BLField "crimeType") ]++  in iPlot sel Circle+++bindLegendDouble :: VegaLite+bindLegendDouble =+  let sel = selection+             . select "mySelection" Single+               [ BindLegend (BLChannelEvent ChColor "dblclick") ]++  in iPlot sel Circle+++bindLegendBoth :: VegaLite+bindLegendBoth =+  let sel = selection+             . select "mySelection"+               Multi+               [ On "click"+               , BindLegend (BLFieldEvent "crimeType" "dblclick")+               ]++  in iPlot sel Circle+++-- lookup into a selection+-- based on https://vega.github.io/vega-lite/docs/lookup.html#lookup-selection+--+lookupSelection1 :: VegaLite+lookupSelection1 =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/stocks.csv"+                 [ CSV, Parse [("date", FoDate "")] ]++      xaxis = position X [PName "date", PmType Temporal, PAxis []]++      t0 = DateTime [DTYear 2005, DTMonthNum 1, DTDate 1]+      selPoint = selection+                 . select "index" Single+                          [ On "mouseover"+                          , Encodings [ChX]+                          , Nearest True+                          , SInit [("x", t0)]+                          ]+      encPoint = encoding+                 . xaxis+                 . opacity [MNumber 0]+      pointSpec = [ encPoint [], selPoint [], mark Point [] ]++      encLine = encoding+                . xaxis+                . position Y [ PName "indexed_price"+                             , PmType Quantitative+                             , PAxis [AxFormat "%"]+                             ]+                . color [ MName "symbol", MmType Nominal]+      transLine = transform+                  . lookupSelection "symbol" "index" "symbol"+                  . calculateAs+                    "datum.index && datum.index.price > 0 ? (datum.price - datum.index.price)/datum.index.price : 0"+                    "indexed_price"+      lineSpec = [ encLine [], transLine [], mark Line [] ]++      encRule = encoding+                . xaxis+                . color [MString "firebrick"]+      transRule = transform+                  . filter (FSelection "index")+      layerRule = layer [ asSpec [ mark Rule [MStrokeWidth 0.5] ]+                        , asSpec [ mark Text [ MAlign AlignCenter+                                             , MFontWeight W100 ]+                                 , encoding+                                   . text [ TName "date"+                                          , TmType Temporal+                                          , TTimeUnit YearMonth+                                          ]+                                   . position Y [PNumber 310]+                                   $ []+                                 ]+                        ]+      ruleSpec = [ encRule [], transRule [], layerRule ]++      layers = layer (map asSpec [pointSpec, lineSpec, ruleSpec])++  in toVegaLite+     [ dvals+     , width 650+     , height 300+     , layers+     ]
tests/LegendTests.hs view
@@ -21,6 +21,9 @@             , ("legend9", legend9)             , ("legend10", legend10)             , ("legend11", legend11)+            , ("legend11d", legend11direct)+            , ("corners1", corners1)+            , ("corners2", corners2)             ]  legendCore :: [LegendProperty] -> VegaLite@@ -104,6 +107,7 @@     in     toVegaLite [ width 300, height 300, dataVals [], enc [], mark Circle [] ] +-- change a number of items using the legend configure legend11 :: VegaLite legend11 =     legendCoreCfg@@ -115,4 +119,68 @@         , LeStrokeWidth 5         , LePadding 30         , LeStrokeDash [ 4, 2, 6, 1 ]+        ]+++-- and now directly, although it looks like Vega Lite 4.0.2+-- doesn't allow all combinations (e.g. stroke width or dash)+-- to be specified.+--+legend11direct :: VegaLite+legend11direct =+    legendCore+        [ LSymbolStrokeWidth 3+        , LSymbolStrokeColor "black"+        , LRowPadding 15+        , LTitlePadding 20+        , LStrokeColor "lightgrey"+        -- , LStrokeWidth 5+        , LPadding 30+        -- , LStrokeDash [ 4, 2, 6, 1 ]+        ]+++-- Show off the corner support+corners1 :: VegaLite+corners1 =+    legendCoreCfg+        [ LeSymbolStrokeWidth 1+        , LeSymbolStrokeColor ""+        , LeRowPadding 15+        , LeTitlePadding 20+        , LeStrokeColor "orange"+        , LeStrokeWidth 2+        , LePadding 30+        , LeStrokeDash [ 4, 2, 6, 1 ]+        , LeCornerRadius 5+        , LeFillColor "pink"+        , LeLabelOpacity 0.6+        , LeLabelFontSize 20+        , LeLabelColor "fireBrick"+        , LeLabelFontWeight W600+        , LeLabelBaseline AlignTop+        , LeLabelAlign AlignRight+        , LeLabelOverlap OGreedy+        ]++corners2 :: VegaLite+corners2 =+  legendCore+        [ LSymbolStrokeWidth 1+        , LSymbolStrokeColor ""+        , LRowPadding 15+        , LTitlePadding 20+        , LStrokeColor "orange"+        -- , LStrokeWidth 2+        , LPadding 30+        -- , LStrokeDash [ 4, 2, 6, 1 ]+        , LCornerRadius 5+        , LFillColor "pink"+        , LLabelOpacity 0.6+        , LLabelFontSize 20+        , LLabelColor "fireBrick"+        , LLabelFontWeight W600+        , LLabelBaseline AlignTop+        , LLabelAlign AlignRight+        , LLabelOverlap OGreedy         ]
tests/NullTests.hs view
@@ -138,7 +138,7 @@     let         config =             configure-                . configuration (RemoveInvalid False)+                . configuration (MarkStyle [ MRemoveInvalid False ])          enc =             encoding@@ -164,7 +164,8 @@     let         config =             configure-                . configuration (RemoveInvalid False)+                -- ensure have at least one test with remove invalid set+                . configuration (MarkStyle [ MRemoveInvalid True ])          trans =             transform
tests/ProjectionTests.hs view
@@ -57,10 +57,12 @@     , worldMapTemplate "ConicConformal" [ PrType ConicConformal, PrClipAngle (Just 65) ]     , worldMapTemplate "ConicEqualArea" [ PrType ConicEqualArea ]     , worldMapTemplate "ConicEquidistant" [ PrType ConicEquidistant ]+    , worldMapTemplate "EqualEarth" [ PrType EqualEarth ]     , worldMapTemplate "Equirectangular" [ PrType Equirectangular ]     , worldMapTemplate "Gnomonic" [ PrType Gnomonic ]     , worldMapTemplate "Identity" [ PrType Identity ]     , worldMapTemplate "Mercator" [ PrType Mercator ]+    , worldMapTemplate "NaturalEarth1" [ PrType NaturalEarth1 ]     , worldMapTemplate "Orthographic" [ PrType Orthographic ]     , worldMapTemplate "Stereographic" [ PrType Stereographic ]     , worldMapTemplate "TransverseMercator" [ PrType TransverseMercator ]@@ -87,7 +89,9 @@             configure                 . configuration (Background "rgb(251,247,238)")                 . configuration (TitleStyle [ TFont "Roboto", TFontWeight W600, TFontSize 18 ])-                . configuration (View [ ViewWidth 500, ViewHeight 300, ViewStroke Nothing ])+                . configuration (View [ ViewContinuousWidth 500+                                      , ViewContinuousHeight 300+                                      , ViewStroke Nothing ])                 . configuration (Autosize [ AFit ])                 . configuration (Projection [ PrType Orthographic, PrRotate 0 0 0 ]) 
tests/ShapeTests.hs view
@@ -38,10 +38,18 @@             , ("point5", point5)             , ("point6", point6)             , ("point7", point7)+            , ("rounded1", rounded1)+            , ("rounded2", rounded2)+            , ("rounded3", rounded3)+            , ("rounded4", rounded4)+            , ("rounded5", rounded5)+            , ("rounded6", rounded6)+            , ("symbols1", symbols1)+            , ("symbols2", symbols2)             ]  -chart :: T.Text -> ([a] -> [LabelledSpec]) -> VegaLite+chart :: T.Text -> ([a] -> [EncodingSpec]) -> VegaLite chart des enc =     toVegaLite         [ description des@@ -316,3 +324,67 @@  point7 :: VegaLite point7 = pointChart "wedge-unfilled" False SymWedge+++rectTest :: [MarkProperty] -> VegaLite+rectTest mps =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json" []+      enc = encoding+            . position X [ PName "Origin", PmType Nominal ]+            . position Y [ PName "Cylinders", PmType Ordinal ]++      -- using MSize here returns the warning+      -- 'Cannot apply size to non-oriented mark "rect".'+      -- from Vega Embed. If we take it out the visualization doesn't+      -- "look as good".+      --+      rect = mark Rect (MSize 30 : MOpacity 0.6 : mps)++  in toVegaLite [ width 200, height 200, dvals, enc [], rect ]+++rounded1, rounded2, rounded3, rounded4, rounded5, rounded6 :: VegaLite+rounded1 = rectTest [ MCornerRadius 8 ]+rounded2 = rectTest [ MCornerRadiusTL 8 ]+rounded3 = rectTest [ MCornerRadiusTR 8 ]+rounded4 = rectTest [ MCornerRadiusBL 8 ]+rounded5 = rectTest [ MCornerRadiusBR 8 ]+rounded6 = rectTest [ MCornerRadius 16, MCornerRadiusBL 0, MCornerRadiusTR 0 ]+++symbols1 :: VegaLite+symbols1 =+  let dvals = dataFromColumns []+              . dataColumn "x" (Numbers [ 0 ])++      shapeSpec sym = asSpec [ mark Point [ MFilled True+                                          , MStroke "black"+                                          , MSize 400+                                          , MShape sym+                                          , MStrokeWidth 0.5+                                          ]+                             ]++      shapeList = [ SymCircle, SymSquare, SymDiamond, SymCross+                  , SymTriangleUp, SymTriangleDown, SymTriangleLeft+                  , SymTriangleRight, SymTriangle, SymArrow+                  , SymWedge, SymStroke, SymPath "M -1 -1 L 1 1" ]++      shapes = map shapeSpec shapeList++  in toVegaLite [ dvals []+                , columns 4+                , vlConcat shapes+                ]++symbols2 :: VegaLite+symbols2 =+  chart "Legend using non-default bordered square symbols"+        (color [ MName "Origin"+               , MmType Nominal+               , MLegend [ LSymbolType SymSquare+                         , LSymbolStrokeColor "black"+                         , LSymbolStrokeWidth 0.5+                         ]+               ]+        )
tests/Test.hs view
@@ -47,6 +47,7 @@ import qualified FillStrokeTests as FST 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 NullTests as NT@@ -117,6 +118,7 @@   , toTests "FillStroke" "fillstroke" FST.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 "Null" "null" NT.testSpecs
tests/TextFormatTests.hs view
@@ -15,6 +15,7 @@ testSpecs :: [(String, VegaLite)] testSpecs = [ ("textFormat1", textFormat1)             , ("textFormat2", textFormat2)+            , ("tstring", tString)             ]  textFormat1 :: VegaLite@@ -22,7 +23,7 @@     let         xs = map (T.pack . show) [1981 .. 2001 :: Int]         ys = map (\n -> 2011 + 1991 - n) [1991 .. 2011]-        +         dataVals =             dataFromColumns []                 . dataColumn "a" (Strings xs)@@ -81,3 +82,20 @@     in     toVegaLite [ width 100, dataVals [], trans []                , mark Bar [], enc [] ]+++-- Add a basic test to try out TString; not really text formatting but related+--+tString :: VegaLite+tString =+  let dvals = dataFromColumns []+                . dataColumn "x" (Numbers [10, 30, 40])+                . dataColumn "y" (Numbers [2, 5, 30])++      enc = encoding+              . position X [ PName "x", PmType Quantitative ]+              . position Y [ PName "y", PmType Quantitative ]+              -- dog symbol+              . text [ TString "🐕" ]++  in toVegaLite [ width 100, height 100, dvals [], enc [], mark Text [] ]
tests/TimeTests.hs view
@@ -28,6 +28,7 @@             , ("timeMinutesSeconds", timeMinutesSeconds)             , ("localTime", localTime)             , ("utcTime", utcTime)+            , ("timeBand", timeBand)             ]  @@ -166,3 +167,21 @@  utcTime :: VegaLite utcTime = parseTime UTC+++timeBand :: VegaLite+timeBand =+  let dvals = dataFromUrl "https://vega.github.io/vega-lite/data/seattle-temps.csv" []++      enc = encoding+            . position X [ PName "date", PTimeUnit Month+                         , PmType Temporal, PBand 0.5 ]+            . position Y [ PName "temp", PAggregate Mean+                         , PmType Quantitative ]++  in toVegaLite+        [ width 400+        , dvals+        , enc []+        , mark Line [ MPoint (PMMarker [ MFill "black" ]) ]+        ]
tests/TooltipTests.hs view
@@ -10,10 +10,12 @@ testSpecs :: [(String, VegaLite)] testSpecs = [ ("tooltip1", tooltip1)             , ("tooltip2", tooltip2)+            , ("notips", notips)             ]-            -tooltip1 :: VegaLite-tooltip1 =+++with :: BuildEncodingSpecs -> VegaLite+with encs =     let         dataVals =             dataFromColumns []@@ -24,25 +26,21 @@             encoding                 . position X [ PName "a", PmType Ordinal ]                 . position Y [ PName "b", PmType Quantitative ]-                . tooltip [ TName "b", TmType Quantitative ]+                . encs     in     toVegaLite [ dataVals [], mark Bar [], enc [] ] -tooltip2 :: VegaLite-tooltip2 =-    let-        dataVals =-            dataFromColumns []-                . dataColumn "a" (Strings [ "A", "B", "C", "D", "E", "F", "G", "H", "I" ])-                . dataColumn "b" (Numbers [ 28, 55, 43, 91, 81, 53, 19, 87, 52 ]) -        enc =-            encoding-                . position X [ PName "a", PmType Ordinal ]-                . position Y [ PName "b", PmType Quantitative ]-                . tooltips+tooltip1 :: VegaLite+tooltip1 = with (tooltip [ TName "b", TmType Quantitative ])+++tooltip2 :: VegaLite+tooltip2 = with (tooltips                     [ [ TName "a", TmType Ordinal ]                     , [ TName "b", TmType Quantitative ]-                    ]-    in-    toVegaLite [ dataVals [], mark Bar [], enc [] ]+                    ])+++notips :: VegaLite+notips = with (tooltip [])
tests/ViewCompositionTests.hs view
@@ -11,6 +11,7 @@  import Prelude hiding (filter, repeat) + testSpecs :: [(String, VegaLite)] testSpecs = [ ("columns1", columns1)             , ("columns2", columns2)@@ -26,45 +27,42 @@  genderChart :: [HeaderProperty] -> [HeaderProperty] -> VegaLite genderChart hdProps cProps =-    let-        conf =-            configure . configuration (HeaderStyle cProps)+  let conf = configure . configuration (HeaderStyle cProps) -        pop =-            dataFromUrl "https://vega.github.io/vega-lite/data/population.json" []+      pop =+          dataFromUrl "https://vega.github.io/vega-lite/data/population.json" [] -        trans =-            transform-                . filter (FExpr "datum.year == 2000")-                . calculateAs "datum.sex == 2 ? 'Female' : 'Male'" "gender"+      trans =+          transform+              . filter (FExpr "datum.year == 2000")+              . calculateAs "datum.sex == 2 ? 'Female' : 'Male'" "gender" -        enc =-            encoding-                . column-                    [ FName "gender"-                    , FmType Nominal-                    , FHeader hdProps-                    ]-                . position X-                    [ PName "age"-                    , PmType Ordinal-                    , PScale [ SRangeStep (Just 17) ]-                    ]-                . position Y-                    [ PName "people"-                    , PmType Quantitative-                    , PAggregate Sum-                    , PAxis [ AxTitle "Population" ]-                    ]-                . color-                    [ MName "gender"-                    , MmType Nominal-                    , MScale [ SRange (RStrings [ "#EA98D2", "#659CCA" ]) ]-                    ]-    in-    toVegaLite [ conf [], pop, trans [], enc [], mark Bar [] ]+      enc =+          encoding+              . column+                  [ FName "gender"+                  , FmType Nominal+                  , FHeader hdProps+                  ]+              . position X+                  [ PName "age"+                  , PmType Ordinal+                  ]+              . position Y+                  [ PName "people"+                  , PmType Quantitative+                  , PAggregate Sum+                  , PAxis [ AxTitle "Population" ]+                  ]+              . color+                  [ MName "gender"+                  , MmType Nominal+                  , MScale [ SRange (RStrings [ "#CC9933", "#3399CC" ]) ]+                  ] +  in toVegaLite [ conf [], pop, trans [], enc [], mark Bar [], widthStep 17 ] + columns1, columns2, columns3, columns4 :: VegaLite columns1 = genderChart [] [] columns2 = genderChart [ HTitleFontSize 20, HLabelFontSize 15 ] []@@ -104,23 +102,31 @@         . dataColumn "val" vals  -grid1 :: VegaLite-grid1 =-    let-        encByCatVal =-            encoding-                . position X [ PName "cat", PmType Ordinal, PAxis [] ]-                . position Y [ PName "val", PmType Quantitative, PAxis [] ]-                . color [ MName "cat", MmType Nominal, MLegend [] ]+encByCatVal :: [EncodingSpec] -> PropertySpec+encByCatVal = encoding+              . position X [ PName "cat", PmType Ordinal, PAxis [] ]+              . position Y [ PName "val", PmType Quantitative, PAxis [] ]+              . color [ MName "cat", MmType Nominal, MLegend [] ] -        specByCatVal =-            asSpec [ width 120, height 120, mark Bar [], encByCatVal [] ]+specByCatVal :: VLSpec+specByCatVal = asSpec [ width 120, height 120, mark Bar [], encByCatVal [] ] -        cfg = configure-                . configuration (HeaderStyle [ HLabelFontSize 0.1 ])-                . configuration (View [ ViewStroke Nothing, ViewHeight 120 ])-                . configuration (FacetStyle [ FSpacing 80, FColumns 5 ])+gridTransform :: PropertySpec+gridTransform = transform+                (calculateAs "datum.row * 1000 + datum.col" "index" []) +gridConfig :: [FacetConfig] -> [ConfigureSpec] -> PropertySpec+gridConfig fopts =+  configure+  . configuration (HeaderStyle [ HLabelFontSize 0.1 ])+  . configuration (View [ ViewStroke Nothing, ViewContinuousHeight 120 ])+  . configuration (FacetStyle fopts)+++grid1 :: VegaLite+grid1 =+    let cfg = gridConfig [ FSpacing 80, FColumns 5 ]+     in     toVegaLite         [ cfg []@@ -136,29 +142,13 @@  grid2 :: VegaLite grid2 =-    let-        encByCatVal =-            encoding-                . position X [ PName "cat", PmType Ordinal, PAxis [] ]-                . position Y [ PName "val", PmType Quantitative, PAxis [] ]-                . color [ MName "cat", MmType Nominal, MLegend [] ]--        specByCatVal =-            asSpec [ width 120, height 120, mark Bar [], encByCatVal [] ]--        cfg = configure-                . configuration (HeaderStyle [ HLabelFontSize 0.1 ])-                . configuration (View [ ViewStroke Nothing, ViewHeight 120 ])-                . configuration (FacetStyle [ FSpacing 80, FColumns 5 ])+    let cfg = gridConfig [ FSpacing 80, FColumns 5 ] -        trans =-            transform-                . calculateAs "datum.row * 1000 + datum.col" "index"     in     toVegaLite         [ cfg []         , dataVals []-        , trans []+        , gridTransform         , columns 5         , specification specByCatVal         , facetFlow [ FName "index", FmType Ordinal, FHeader [ HNoTitle ] ]@@ -167,80 +157,53 @@  -- This has been changed from the Elm version so that it validates -- against the v3.4.0 specification.+-- (not sure if this is still a valid comment) -- grid3 :: VegaLite grid3 =-    let-        encByCatVal =-            encoding-                . position X [ PName "cat", PmType Ordinal, PAxis [] ]-                . position Y [ PName "val", PmType Quantitative, PAxis [] ]-                . color [ MName "cat", MmType Nominal, MLegend [] ]--        specByCatVal =-            asSpec [ width 120, height 120, mark Bar [], encByCatVal [] ]--        cfg = configure-                . configuration (HeaderStyle [ HLabelFontSize 0.1 ])-                . configuration (View [ ViewStroke Nothing, ViewHeight 120 ])-                . configuration (FacetStyle [ FSpacing 80 ])+    let cfg = gridConfig [ FSpacing 80 ] -        trans =-            transform-                . calculateAs "datum.row * 1000 + datum.col" "index"     in     toVegaLite         [ cfg []         , dataVals []-        , trans []+        , gridTransform         , columns 5         , specification specByCatVal         , facetFlow [ FName "index", FmType Ordinal, FHeader [ HNoTitle ] ]         ]  +carGrid :: Arrangement -> [PropertySpec] -> VegaLite+carGrid rpt opts =+  let carData = dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"++      enc = encoding+            . position X [ PRepeat rpt, PmType Quantitative, PBin [] ]+            . position Y [ PmType Quantitative, PAggregate Count ]+            . color [ MName "Origin", MmType Nominal ]++      spec = asSpec [ carData [], mark Bar [], enc [] ]++  in toVegaLite (specification spec : opts)++ grid4 :: VegaLite grid4 =-    let-        carData =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"--        enc =-            encoding-                . position X [ PRepeat Flow, PmType Quantitative, PBin [] ]-                . position Y [ PmType Quantitative, PAggregate Count ]-                . color [ MName "Origin", MmType Nominal ]+  let opts = [ columns 3+             , repeatFlow [ "Horsepower", "Miles_per_Gallon", "Acceleration", "Displacement", "Weight_in_lbs" ]+             ] -        spec =-            asSpec [ carData [], mark Bar [], enc [] ]-    in-    toVegaLite-        [ columns 3-        , repeatFlow [ "Horsepower", "Miles_per_Gallon", "Acceleration", "Displacement", "Weight_in_lbs" ]-        , specification spec-        ]+  in carGrid Flow opts   grid5 :: VegaLite grid5 =-    let-        carData =-            dataFromUrl "https://vega.github.io/vega-lite/data/cars.json"--        enc =-            encoding-                . position X [ PRepeat Row, PmType Quantitative, PBin [] ]-                . position Y [ PmType Quantitative, PAggregate Count ]-                . color [ MName "Origin", MmType Nominal ]+  let opts = [ repeat+               [ RowFields [ "Horsepower", "Miles_per_Gallon", "Acceleration", "Displacement", "Weight_in_lbs" ]+               ]+             ] -        spec =-            asSpec [ carData [], mark Bar [], enc [] ]-    in-    toVegaLite-        [ repeat-            [ RowFields [ "Horsepower", "Miles_per_Gallon", "Acceleration", "Displacement", "Weight_in_lbs" ]-            ]-        , specification spec-        ]+  in carGrid Row opts  
tests/WindowTransformTests.hs view
@@ -38,9 +38,9 @@         enc =             encoding                 . position X [ PName "PercentOfTotal", PmType Quantitative, PAxis [ AxTitle "% of total time" ] ]-                . position Y [ PName "Activity", PmType Nominal, PScale [ SRangeStep (Just 12) ] ]+                . position Y [ PName "Activity", PmType Nominal ]     in-    toVegaLite [ dataVals [], trans [], mark Bar [], enc [] ]+    toVegaLite [ dataVals [], trans [], mark Bar [], heightStep 12, enc [] ]   window2 :: VegaLite@@ -228,9 +228,9 @@         enc =             encoding                 . position X [ PName "PercentOfTotal", PmType Quantitative, PAxis [ AxTitle "% of total Time" ] ]-                . position Y [ PName "Activity", PmType Nominal, PScale [ SRangeStep (Just 12) ] ]+                . position Y [ PName "Activity", PmType Nominal ]                 -    in toVegaLite [ dataVals [], trans [], enc [], mark Bar [] ]+    in toVegaLite [ dataVals [], trans [], enc [], mark Bar [], heightStep 12 ]  joinAggregate2 :: VegaLite joinAggregate2 =
tests/specs/axis/axis1.vl view
@@ -507,7 +507,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "x",
tests/specs/axis/axis2.vl view
@@ -507,7 +507,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "catX",
tests/specs/axis/axis3.vl view
@@ -507,7 +507,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
tests/specs/axis/axis4.vl view
@@ -507,7 +507,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "x",
tests/specs/axis/axis5.vl view
@@ -507,7 +507,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "catX",
tests/specs/axis/axis6.vl view
@@ -55,7 +55,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
+ tests/specs/axis/axis7.vl view
@@ -0,0 +1,524 @@+{+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "labelExpr": "datum.value / 100"+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axis8.vl view
@@ -0,0 +1,524 @@+{+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "catX",+            "type": "ordinal",+            "axis": {+                "labelExpr": "'number' + datum.label"+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/axisOverlapGreedy.vl view
@@ -0,0 +1,46 @@+{+    "mark": "circle",+    "data": {+        "values": [+            {+                "x": 0.1,+                "y": 100+            },+            {+                "x": 0.11,+                "y": 101+            },+            {+                "x": 0.2,+                "y": 102+            },+            {+                "x": 0.21,+                "y": 103+            },+            {+                "x": 0.5,+                "y": 101+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "labelOverlap": "greedy",+                "labelFontSize": 20+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "labelOverlap": "greedy",+                "labelFontSize": 20+            }+        }+    }+}
+ tests/specs/axis/axisOverlapNone.vl view
@@ -0,0 +1,46 @@+{+    "mark": "circle",+    "data": {+        "values": [+            {+                "x": 0.1,+                "y": 100+            },+            {+                "x": 0.11,+                "y": 101+            },+            {+                "x": 0.2,+                "y": 102+            },+            {+                "x": 0.21,+                "y": 103+            },+            {+                "x": 0.5,+                "y": 101+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "labelOverlap": false,+                "labelFontSize": 20+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "labelOverlap": false,+                "labelFontSize": 20+            }+        }+    }+}
+ tests/specs/axis/axisOverlapParity.vl view
@@ -0,0 +1,46 @@+{+    "mark": "circle",+    "data": {+        "values": [+            {+                "x": 0.1,+                "y": 100+            },+            {+                "x": 0.11,+                "y": 101+            },+            {+                "x": 0.2,+                "y": 102+            },+            {+                "x": 0.21,+                "y": 103+            },+            {+                "x": 0.5,+                "y": 101+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative",+            "axis": {+                "labelOverlap": true,+                "labelFontSize": 20+            }+        },+        "y": {+            "field": "y",+            "type": "quantitative",+            "axis": {+                "labelOverlap": true,+                "labelFontSize": 20+            }+        }+    }+}
+ tests/specs/axis/responsiveHeight.vl view
@@ -0,0 +1,522 @@+{+    "height": "container",+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/axis/responsiveWidth.vl view
@@ -0,0 +1,522 @@+{+    "mark": {+        "point": true,+        "type": "line"+    },+    "data": {+        "values": [+            {+                "x": 1,+                "catX": "1",+                "y": 1+            },+            {+                "x": 2,+                "catX": "2",+                "y": 2+            },+            {+                "x": 3,+                "catX": "3",+                "y": 3+            },+            {+                "x": 4,+                "catX": "4",+                "y": 4+            },+            {+                "x": 5,+                "catX": "5",+                "y": 5+            },+            {+                "x": 6,+                "catX": "6",+                "y": 6+            },+            {+                "x": 7,+                "catX": "7",+                "y": 7+            },+            {+                "x": 8,+                "catX": "8",+                "y": 8+            },+            {+                "x": 9,+                "catX": "9",+                "y": 9+            },+            {+                "x": 10,+                "catX": "10",+                "y": 10+            },+            {+                "x": 11,+                "catX": "11",+                "y": 11+            },+            {+                "x": 12,+                "catX": "12",+                "y": 12+            },+            {+                "x": 13,+                "catX": "13",+                "y": 13+            },+            {+                "x": 14,+                "catX": "14",+                "y": 14+            },+            {+                "x": 15,+                "catX": "15",+                "y": 15+            },+            {+                "x": 16,+                "catX": "16",+                "y": 16+            },+            {+                "x": 17,+                "catX": "17",+                "y": 17+            },+            {+                "x": 18,+                "catX": "18",+                "y": 18+            },+            {+                "x": 19,+                "catX": "19",+                "y": 19+            },+            {+                "x": 20,+                "catX": "20",+                "y": 20+            },+            {+                "x": 21,+                "catX": "21",+                "y": 21+            },+            {+                "x": 22,+                "catX": "22",+                "y": 22+            },+            {+                "x": 23,+                "catX": "23",+                "y": 23+            },+            {+                "x": 24,+                "catX": "24",+                "y": 24+            },+            {+                "x": 25,+                "catX": "25",+                "y": 25+            },+            {+                "x": 26,+                "catX": "26",+                "y": 26+            },+            {+                "x": 27,+                "catX": "27",+                "y": 27+            },+            {+                "x": 28,+                "catX": "28",+                "y": 28+            },+            {+                "x": 29,+                "catX": "29",+                "y": 29+            },+            {+                "x": 30,+                "catX": "30",+                "y": 30+            },+            {+                "x": 31,+                "catX": "31",+                "y": 31+            },+            {+                "x": 32,+                "catX": "32",+                "y": 32+            },+            {+                "x": 33,+                "catX": "33",+                "y": 33+            },+            {+                "x": 34,+                "catX": "34",+                "y": 34+            },+            {+                "x": 35,+                "catX": "35",+                "y": 35+            },+            {+                "x": 36,+                "catX": "36",+                "y": 36+            },+            {+                "x": 37,+                "catX": "37",+                "y": 37+            },+            {+                "x": 38,+                "catX": "38",+                "y": 38+            },+            {+                "x": 39,+                "catX": "39",+                "y": 39+            },+            {+                "x": 40,+                "catX": "40",+                "y": 40+            },+            {+                "x": 41,+                "catX": "41",+                "y": 41+            },+            {+                "x": 42,+                "catX": "42",+                "y": 42+            },+            {+                "x": 43,+                "catX": "43",+                "y": 43+            },+            {+                "x": 44,+                "catX": "44",+                "y": 44+            },+            {+                "x": 45,+                "catX": "45",+                "y": 45+            },+            {+                "x": 46,+                "catX": "46",+                "y": 46+            },+            {+                "x": 47,+                "catX": "47",+                "y": 47+            },+            {+                "x": 48,+                "catX": "48",+                "y": 48+            },+            {+                "x": 49,+                "catX": "49",+                "y": 49+            },+            {+                "x": 50,+                "catX": "50",+                "y": 50+            },+            {+                "x": 51,+                "catX": "51",+                "y": 51+            },+            {+                "x": 52,+                "catX": "52",+                "y": 52+            },+            {+                "x": 53,+                "catX": "53",+                "y": 53+            },+            {+                "x": 54,+                "catX": "54",+                "y": 54+            },+            {+                "x": 55,+                "catX": "55",+                "y": 55+            },+            {+                "x": 56,+                "catX": "56",+                "y": 56+            },+            {+                "x": 57,+                "catX": "57",+                "y": 57+            },+            {+                "x": 58,+                "catX": "58",+                "y": 58+            },+            {+                "x": 59,+                "catX": "59",+                "y": 59+            },+            {+                "x": 60,+                "catX": "60",+                "y": 60+            },+            {+                "x": 61,+                "catX": "61",+                "y": 61+            },+            {+                "x": 62,+                "catX": "62",+                "y": 62+            },+            {+                "x": 63,+                "catX": "63",+                "y": 63+            },+            {+                "x": 64,+                "catX": "64",+                "y": 64+            },+            {+                "x": 65,+                "catX": "65",+                "y": 65+            },+            {+                "x": 66,+                "catX": "66",+                "y": 66+            },+            {+                "x": 67,+                "catX": "67",+                "y": 67+            },+            {+                "x": 68,+                "catX": "68",+                "y": 68+            },+            {+                "x": 69,+                "catX": "69",+                "y": 69+            },+            {+                "x": 70,+                "catX": "70",+                "y": 70+            },+            {+                "x": 71,+                "catX": "71",+                "y": 71+            },+            {+                "x": 72,+                "catX": "72",+                "y": 72+            },+            {+                "x": 73,+                "catX": "73",+                "y": 73+            },+            {+                "x": 74,+                "catX": "74",+                "y": 74+            },+            {+                "x": 75,+                "catX": "75",+                "y": 75+            },+            {+                "x": 76,+                "catX": "76",+                "y": 76+            },+            {+                "x": 77,+                "catX": "77",+                "y": 77+            },+            {+                "x": 78,+                "catX": "78",+                "y": 78+            },+            {+                "x": 79,+                "catX": "79",+                "y": 79+            },+            {+                "x": 80,+                "catX": "80",+                "y": 80+            },+            {+                "x": 81,+                "catX": "81",+                "y": 81+            },+            {+                "x": 82,+                "catX": "82",+                "y": 82+            },+            {+                "x": 83,+                "catX": "83",+                "y": 83+            },+            {+                "x": 84,+                "catX": "84",+                "y": 84+            },+            {+                "x": 85,+                "catX": "85",+                "y": 85+            },+            {+                "x": 86,+                "catX": "86",+                "y": 86+            },+            {+                "x": 87,+                "catX": "87",+                "y": 87+            },+            {+                "x": 88,+                "catX": "88",+                "y": 88+            },+            {+                "x": 89,+                "catX": "89",+                "y": 89+            },+            {+                "x": 90,+                "catX": "90",+                "y": 90+            },+            {+                "x": 91,+                "catX": "91",+                "y": 91+            },+            {+                "x": 92,+                "catX": "92",+                "y": 92+            },+            {+                "x": 93,+                "catX": "93",+                "y": 93+            },+            {+                "x": 94,+                "catX": "94",+                "y": 94+            },+            {+                "x": 95,+                "catX": "95",+                "y": 95+            },+            {+                "x": 96,+                "catX": "96",+                "y": 96+            },+            {+                "x": 97,+                "catX": "97",+                "y": 97+            },+            {+                "x": 98,+                "catX": "98",+                "y": 98+            },+            {+                "x": 99,+                "catX": "99",+                "y": 99+            },+            {+                "x": 100,+                "catX": "100",+                "y": 100+            }+        ]+    },+    "width": "container",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
tests/specs/axis/zorder.vl view
@@ -29,7 +29,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/color/customContinuous.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/customDiscrete.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Origin",
tests/specs/color/defContinuous.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/defNominal.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Origin",
tests/specs/color/defOrdinal.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Cylinders",
tests/specs/color/gamma1.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/gamma2.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/gamma3.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/gamma4.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/gamma5.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/interp1.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/interp2.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/interp3.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/interp4.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/interp5.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/interp6.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/interp7.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/namedContinuous1.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/namedContinuous2.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/namedContinuous3.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/namedContinuous4.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/scale1.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/scale3.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/scale4.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/scale5.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/scale6.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Acceleration",
tests/specs/color/scale7.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "accelerationZScore",
tests/specs/color/scale8.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "accelerationZScore",
tests/specs/composite/boxplot1.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "age",
tests/specs/composite/boxplot2.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "age",
tests/specs/composite/boxplot3.vl view
@@ -25,7 +25,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "age",
tests/specs/composite/errorband1.vl view
@@ -8,7 +8,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Year",
tests/specs/composite/errorband2.vl view
@@ -8,7 +8,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Year",
tests/specs/composite/errorbar1.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "yield",
tests/specs/composite/errorbar2.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "yield",
tests/specs/composite/errorbar3.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
+ tests/specs/composite/errorbar4.vl view
@@ -0,0 +1,73 @@+{+    "data": {+        "values": [+            {+                "yieldError2": -10.55,+                "yieldError": 7.55,+                "variety": "Glabron",+                "yield": 32.4+            },+            {+                "yieldError2": -3.98,+                "yieldError": 6.98,+                "variety": "Manchuria",+                "yield": 30.97+            },+            {+                "yieldError2": -0.92,+                "yieldError": 3.92,+                "variety": "No. 457",+                "yield": 33.96+            },+            {+                "yieldError2": -15.97,+                "yieldError": 11.97,+                "variety": "No. 462",+                "yield": 30.45+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "type": "errorbar",+                "ticks": {}+            },+            "encoding": {+                "x": {+                    "field": "yield",+                    "scale": {+                        "zero": false+                    },+                    "type": "quantitative"+                },+                "xError": {+                    "field": "yieldError"+                },+                "y": {+                    "field": "variety",+                    "type": "ordinal"+                }+            }+        },+        {+            "mark": {+                "color": "black",+                "type": "point",+                "filled": true+            },+            "encoding": {+                "x": {+                    "field": "yield",+                    "type": "quantitative"+                },+                "y": {+                    "field": "variety",+                    "type": "ordinal"+                }+            }+        }+    ],+    "description": "Symetric error bars encoded with xError channel"+}
+ tests/specs/composite/errorbar5.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "yieldError2": -10.55,+                "yieldError": 7.55,+                "variety": "Glabron",+                "yield": 32.4+            },+            {+                "yieldError2": -3.98,+                "yieldError": 6.98,+                "variety": "Manchuria",+                "yield": 30.97+            },+            {+                "yieldError2": -0.92,+                "yieldError": 3.92,+                "variety": "No. 457",+                "yield": 33.96+            },+            {+                "yieldError2": -15.97,+                "yieldError": 11.97,+                "variety": "No. 462",+                "yield": 30.45+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "type": "errorbar",+                "ticks": {}+            },+            "encoding": {+                "xError2": {+                    "field": "yieldError2"+                },+                "x": {+                    "field": "yield",+                    "scale": {+                        "zero": false+                    },+                    "type": "quantitative"+                },+                "xError": {+                    "field": "yieldError"+                },+                "y": {+                    "field": "variety",+                    "type": "ordinal"+                }+            }+        },+        {+            "mark": {+                "color": "black",+                "type": "point",+                "filled": true+            },+            "encoding": {+                "x": {+                    "field": "yield",+                    "type": "quantitative"+                },+                "y": {+                    "field": "variety",+                    "type": "ordinal"+                }+            }+        }+    ],+    "description": "Asymetric error bars encoded with xError and xError2 channels"+}
+ tests/specs/composite/errorbar6.vl view
@@ -0,0 +1,73 @@+{+    "data": {+        "values": [+            {+                "yieldError2": -10.55,+                "yieldError": 7.55,+                "variety": "Glabron",+                "yield": 32.4+            },+            {+                "yieldError2": -3.98,+                "yieldError": 6.98,+                "variety": "Manchuria",+                "yield": 30.97+            },+            {+                "yieldError2": -0.92,+                "yieldError": 3.92,+                "variety": "No. 457",+                "yield": 33.96+            },+            {+                "yieldError2": -15.97,+                "yieldError": 11.97,+                "variety": "No. 462",+                "yield": 30.45+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "type": "errorbar",+                "ticks": {}+            },+            "encoding": {+                "yError": {+                    "field": "yieldError"+                },+                "x": {+                    "field": "variety",+                    "type": "ordinal"+                },+                "y": {+                    "field": "yield",+                    "scale": {+                        "zero": false+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "black",+                "type": "point",+                "filled": true+            },+            "encoding": {+                "x": {+                    "field": "variety",+                    "type": "ordinal"+                },+                "y": {+                    "field": "yield",+                    "type": "quantitative"+                }+            }+        }+    ],+    "description": "Symetric error bars encoded with yError channel"+}
+ tests/specs/composite/errorbar7.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "yieldError2": -10.55,+                "yieldError": 7.55,+                "variety": "Glabron",+                "yield": 32.4+            },+            {+                "yieldError2": -3.98,+                "yieldError": 6.98,+                "variety": "Manchuria",+                "yield": 30.97+            },+            {+                "yieldError2": -0.92,+                "yieldError": 3.92,+                "variety": "No. 457",+                "yield": 33.96+            },+            {+                "yieldError2": -15.97,+                "yieldError": 11.97,+                "variety": "No. 462",+                "yield": 30.45+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "type": "errorbar",+                "ticks": {}+            },+            "encoding": {+                "yError2": {+                    "field": "yieldError2"+                },+                "yError": {+                    "field": "yieldError"+                },+                "x": {+                    "field": "variety",+                    "type": "ordinal"+                },+                "y": {+                    "field": "yield",+                    "scale": {+                        "zero": false+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "black",+                "type": "point",+                "filled": true+            },+            "encoding": {+                "x": {+                    "field": "variety",+                    "type": "ordinal"+                },+                "y": {+                    "field": "yield",+                    "type": "quantitative"+                }+            }+        }+    ],+    "description": "Asymetric error bars encoded with yError and yError2 channels"+}
+ tests/specs/conditional/axisCondition1.vl view
@@ -0,0 +1,42 @@+{+    "height": 600,+    "mark": {+        "opacity": 0.1,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "width": 600,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "IMDB_Rating",+            "type": "quantitative",+            "axis": {+                "tickCount": 20,+                "gridDash": {+                    "value": [],+                    "condition": {+                        "value": [+                            5,+                            5+                        ],+                        "test": "datum.value <= 5"+                    }+                },+                "gridColor": {+                    "value": "red",+                    "condition": {+                        "value": "green",+                        "test": "datum.value <= 7"+                    }+                }+            }+        },+        "y": {+            "field": "Rotten_Tomatoes_Rating",+            "type": "quantitative"+        }+    }+}
+ tests/specs/conditional/axisCondition2.vl view
@@ -0,0 +1,56 @@+{+    "height": 600,+    "mark": {+        "opacity": 0.1,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "width": 600,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "IMDB_Rating",+            "type": "quantitative",+            "axis": {+                "tickWidth": {+                    "value": 2,+                    "condition": {+                        "value": 5,+                        "test": "datum.label =='4.0'"+                    }+                },+                "tickDash": {+                    "value": [],+                    "condition": {+                        "value": [+                            2,+                            2+                        ],+                        "test": "(datum.value >= 5) && (datum.value <= 8)"+                    }+                },+                "tickCount": 20,+                "tickOpacity": {+                    "value": 0.8,+                    "condition": {+                        "value": 0.3,+                        "test": "datum.value >=8"+                    }+                },+                "tickColor": {+                    "value": "blue",+                    "condition": {+                        "value": "red",+                        "test": "datum.value <= 2"+                    }+                }+            }+        },+        "y": {+            "field": "Rotten_Tomatoes_Rating",+            "type": "quantitative"+        }+    }+}
+ tests/specs/conditional/axisCondition3.vl view
@@ -0,0 +1,81 @@+{+    "height": 600,+    "mark": {+        "opacity": 0.1,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "width": 600,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "IMDB_Rating",+            "type": "quantitative",+            "axis": {+                "labelOpacity": {+                    "value": 0.8,+                    "condition": {+                        "value": 0.3,+                        "test": "datum.value >=9"+                    }+                },+                "labelFontStyle": {+                    "value": "italic",+                    "condition": {+                        "value": "normal",+                        "test": "datum.value <=8"+                    }+                },+                "labelColor": {+                    "value": "blue",+                    "condition": {+                        "value": "red",+                        "test": "datum.value <= 2"+                    }+                },+                "tickCount": 20,+                "labelFontWeight": {+                    "value": 100,+                    "condition": {+                        "value": "bold",+                        "test": "datum.label =='4.0'"+                    }+                },+                "labelBaseline": {+                    "value": "bottom",+                    "condition": {+                        "value": "top",+                        "test": "datum.value <= 3"+                    }+                },+                "labelFont": {+                    "value": "sans-serif",+                    "condition": {+                        "value": "serif",+                        "test": "datum.value <= 4"+                    }+                },+                "labelFontSize": {+                    "value": 18,+                    "condition": {+                        "value": 12,+                        "test": "datum.value <= 6"+                    }+                },+                "labelAlign": {+                    "value": "left",+                    "condition": {+                        "value": "right",+                        "test": "datum.value <= 1"+                    }+                }+            }+        },+        "y": {+            "field": "Rotten_Tomatoes_Rating",+            "type": "quantitative"+        }+    }+}
+ tests/specs/conditional/axisDateCondition1.vl view
@@ -0,0 +1,43 @@+{+    "mark": {+        "borders": {},+        "extent": "iqr",+        "interpolate": "monotone",+        "type": "errorband"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 600,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "Year",+            "timeUnit": "year",+            "type": "temporal",+            "axis": {+                "gridWidth": {+                    "value": 1,+                    "condition": {+                        "value": 4,+                        "test": {+                            "equal": {+                                "date": 1,+                                "month": "Jan"+                            },+                            "field": "value",+                            "timeUnit": "monthdate"+                        }+                    }+                }+            }+        },+        "y": {+            "field": "Miles_per_Gallon",+            "scale": {+                "zero": false+            },+            "type": "quantitative"+        }+    }+}
tests/specs/conditional/bindScales1.vl view
@@ -5,7 +5,7 @@         "url": "https://vega.github.io/vega-lite/data/cars.json"     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "myZoomPan": {             "bind": "scales",
tests/specs/conditional/bindScales2.vl view
@@ -5,7 +5,7 @@         "url": "https://vega.github.io/vega-lite/data/cars.json"     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "myZoomPan": {             "clear": "click[event.shiftKey]",
tests/specs/conditional/markCondition1.vl view
@@ -1,12 +1,19 @@ {     "config": {-        "invalidValues": null+        "mark": {+            "invalid": null+        }     },-    "mark": "point",+    "mark": {+        "tooltip": {+            "content": "encoding"+        },+        "type": "point"+    },     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "value": "#0099ee",
tests/specs/conditional/markCondition2.vl view
@@ -26,7 +26,7 @@         ]     },     "width": 400,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "value": "black",
tests/specs/conditional/selectionCondition1.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "alex": {             "type": "interval",
tests/specs/conditional/selectionCondition2.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "alex": {             "type": "interval",
tests/specs/conditional/selectionCondition3.vl view
@@ -59,5 +59,5 @@             }         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/conditional/selectionCondition4.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "mySelection": {             "clear": false,
tests/specs/conditional/selectionCondition5.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "mySelection": {             "empty": "none",
tests/specs/config/axisCfg1.vl view
@@ -17,7 +17,7 @@         "url": "https://vega.github.io/vega-lite/data/cars.json"     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "title": "Car Scatter",     "encoding": {         "color": {
tests/specs/config/dark.vl view
@@ -107,5 +107,5 @@             "shape": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/config/default.vl view
@@ -81,5 +81,5 @@             "shape": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/config/mark1.vl view
@@ -85,5 +85,5 @@             "shape": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/config/mark2.vl view
@@ -98,5 +98,5 @@             "shape": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/config/padding.vl view
@@ -19,7 +19,7 @@         "url": "https://vega.github.io/vega-lite/data/cars.json"     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "title": "Car Scatter",     "encoding": {         "color": {
+ tests/specs/config/paddingContent.vl view
@@ -0,0 +1,42 @@+{+    "height": 200,+    "config": {+        "autosize": {+            "contains": "content"+        },+        "padding": {+            "bottom": 0,+            "left": 90,+            "right": 30,+            "top": 60+        }+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/paddingNone.vl view
@@ -0,0 +1,42 @@+{+    "height": 200,+    "config": {+        "autosize": {+            "type": "none"+        },+        "padding": {+            "bottom": 0,+            "left": 90,+            "right": 30,+            "top": 60+        }+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/paddingPad.vl view
@@ -0,0 +1,42 @@+{+    "height": 200,+    "config": {+        "autosize": {+            "type": "pad"+        },+        "padding": {+            "bottom": 0,+            "left": 90,+            "right": 30,+            "top": 60+        }+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/paddingPadding.vl view
@@ -0,0 +1,42 @@+{+    "height": 200,+    "config": {+        "autosize": {+            "contains": "padding"+        },+        "padding": {+            "bottom": 0,+            "left": 90,+            "right": 30,+            "top": 60+        }+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/paddingResize.vl view
@@ -0,0 +1,42 @@+{+    "height": 200,+    "config": {+        "autosize": {+            "resize": true+        },+        "padding": {+            "bottom": 0,+            "left": 90,+            "right": 30,+            "top": 60+        }+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/paddingx.vl view
@@ -0,0 +1,42 @@+{+    "height": 200,+    "config": {+        "autosize": {+            "type": "fit-x"+        },+        "padding": {+            "bottom": 0,+            "left": 90,+            "right": 30,+            "top": 60+        }+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/paddingy.vl view
@@ -0,0 +1,42 @@+{+    "height": 200,+    "config": {+        "autosize": {+            "type": "fit-y"+        },+        "padding": {+            "bottom": 0,+            "left": 90,+            "right": 30,+            "top": 60+        }+    },+    "mark": {+        "size": 100,+        "type": "point"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Car Scatter",+    "encoding": {+        "color": {+            "field": "Cylinders",+            "type": "ordinal"+        },+        "shape": {+            "field": "Origin",+            "type": "nominal"+        },+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/titleCfg1.vl view
@@ -0,0 +1,29 @@+{+    "height": 200,+    "mark": "circle",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": {+        "text": [+            "Car",+            "Scatter"+        ],+        "subtitle": [+            "A subtitle",+            "also over two lines"+        ]+    },+    "encoding": {+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/titleCfg2.vl view
@@ -0,0 +1,40 @@+{+    "height": 200,+    "mark": "circle",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": {+        "dx": -30,+        "subtitleFontWeight": 900,+        "subtitleFont": "serif",+        "subtitleFontSize": 10,+        "subtitleLineHeight": 18,+        "dy": 10,+        "text": [+            "Car",+            "Scatter"+        ],+        "subtitlePadding": 60,+        "anchor": "end",+        "subtitle": [+            "A subtitle",+            "also over two lines"+        ],+        "subtitleFontStyle": "italic",+        "subtitleColor": "red",+        "lineHeight": 20+    },+    "encoding": {+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
+ tests/specs/config/titleCfg3.vl view
@@ -0,0 +1,44 @@+{+    "height": 200,+    "config": {+        "title": {+            "dx": -30,+            "subtitleFontWeight": 900,+            "subtitleFont": "serif",+            "subtitleFontSize": 10,+            "subtitleLineHeight": 18,+            "dy": 10,+            "subtitlePadding": 60,+            "anchor": "end",+            "subtitleFontStyle": "italic",+            "subtitleColor": "red",+            "lineHeight": 20+        }+    },+    "mark": "circle",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/cars.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": {+        "text": [+            "Car",+            "Scatter"+        ],+        "subtitle": [+            "A subtitle",+            "also over two lines"+        ]+    },+    "encoding": {+        "x": {+            "field": "Horsepower",+            "type": "quantitative"+        },+        "y": {+            "field": "Miles_per_Gallon",+            "type": "quantitative"+        }+    }+}
tests/specs/config/vbTest.vl view
@@ -104,6 +104,9 @@                 "strokeOpacity": 1,                 "fillOpacity": 0.1             }+        },+        "view": {+            "fill": "#feb"         }     },     "data": {@@ -115,6 +118,6 @@             "shape": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "background": "yellow" }
tests/specs/data/annotate1.vl view
@@ -23,7 +23,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar",
tests/specs/data/bin1.vl view
@@ -44,7 +44,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x2": {             "field": "bin_end"
tests/specs/data/bin2.vl view
@@ -95,7 +95,7 @@         ]     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "x",
tests/specs/data/bin3.vl view
@@ -218,7 +218,7 @@         ]     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "x",
tests/specs/data/data1.vl view
@@ -16,7 +16,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data10.vl view
@@ -3,7 +3,7 @@     "data": {         "name": "myData3"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data2.vl view
@@ -16,7 +16,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data3.vl view
@@ -16,7 +16,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data4.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "data/dataTest.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data5.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "data/dataTest.tsv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data6.vl view
@@ -7,7 +7,7 @@             "delimiter": ","         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data7.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "data/dataTest.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data8.vl view
@@ -3,7 +3,7 @@     "data": {         "name": "myData1"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/data9.vl view
@@ -3,7 +3,7 @@     "data": {         "name": "myData2"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/filter1.vl view
@@ -45,7 +45,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "a",
tests/specs/data/filter2.vl view
@@ -64,7 +64,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "a",
tests/specs/data/flatten1.vl view
@@ -39,7 +39,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "key",
tests/specs/data/fold1.vl view
@@ -26,7 +26,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "country",
tests/specs/data/geodata1.vl view
@@ -14,7 +14,7 @@         }     },     "width": 700,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "id",
tests/specs/data/geodata2.vl view
@@ -84,7 +84,7 @@         }     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic"     },
tests/specs/data/impute1.vl view
@@ -49,7 +49,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/impute2.vl view
@@ -53,7 +53,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/impute3.vl view
@@ -54,7 +54,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/impute4.vl view
@@ -39,7 +39,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/impute5.vl view
@@ -39,7 +39,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/impute6.vl view
@@ -39,7 +39,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/impute7.vl view
@@ -39,7 +39,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/impute8.vl view
@@ -39,7 +39,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "c",
tests/specs/data/namedData1.vl view
@@ -41,7 +41,7 @@         ],         "name": "source"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "a",
tests/specs/data/namedData2.vl view
@@ -4,7 +4,7 @@         "url": "data/dataTest.tsv",         "name": "myName"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/namedData3.vl view
@@ -4,7 +4,7 @@         "values": [],         "name": "source"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "cat",
tests/specs/data/null1.vl view
@@ -35,7 +35,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "x",
+ tests/specs/data/pivot1.vl view
@@ -0,0 +1,59 @@+{+    "repeat": [+        "gold",+        "silver"+    ],+    "spec": {+        "transform": [+            {+                "groupby": [+                    "country"+                ],+                "value": "count",+                "pivot": "medalType"+            }+        ],+        "mark": "bar",+        "data": {+            "values": [+                {+                    "country": "USA",+                    "count": 10,+                    "medalType": "gold"+                },+                {+                    "country": "USA",+                    "count": 20,+                    "medalType": "silver"+                },+                {+                    "country": "Canada",+                    "count": 7,+                    "medalType": "gold"+                },+                {+                    "country": "Canada",+                    "count": 26,+                    "medalType": "silver"+                }+            ]+        },+        "encoding": {+            "color": {+                "field": "country",+                "type": "nominal"+            },+            "x": {+                "field": "country",+                "type": "nominal"+            },+            "y": {+                "field": {+                    "repeat": "repeat"+                },+                "type": "quantitative"+            }+        }+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json"+}
+ tests/specs/data/pivotDocs.vl view
@@ -0,0 +1,57 @@+{+    "transform": [+        {+            "groupby": [+                "city"+            ],+            "value": "temperature",+            "pivot": "year"+        }+    ],+    "mark": "circle",+    "data": {+        "values": [+            {+                "temperature": 12,+                "year": 2017,+                "city": "Bristol"+            },+            {+                "temperature": 14,+                "year": 2018,+                "city": "Bristol"+            },+            {+                "temperature": 11,+                "year": 2017,+                "city": "Sheffield"+            },+            {+                "temperature": 13,+                "year": 2018,+                "city": "Sheffield"+            },+            {+                "temperature": 7,+                "year": 2017,+                "city": "Glasgow"+            },+            {+                "temperature": 10,+                "year": 2018,+                "city": "Glasgow"+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "2017",+            "type": "quantitative"+        },+        "y": {+            "field": "city",+            "type": "nominal"+        }+    }+}
tests/specs/data/sample1.vl view
@@ -35,5 +35,5 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/data/sequence1.vl view
@@ -13,7 +13,7 @@             "stop": 12.7         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "data",
tests/specs/data/sequence2.vl view
@@ -14,7 +14,7 @@             "stop": 12.7         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "u",
tests/specs/fillstroke/combined1.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/combined2.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/combined3.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/default.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/fill1.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/fill2.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/fill3.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/geo1.vl view
@@ -59,5 +59,5 @@         }     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/fillstroke/geo2.vl view
@@ -59,7 +59,7 @@         }     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "features.geometry.type",
+ tests/specs/fillstroke/gradient1.vl view
@@ -0,0 +1,58 @@+{+    "mark": {+        "color": {+            "x2": 1,+            "y1": 0,+            "stops": [+                {+                    "color": "red",+                    "offset": 0+                },+                {+                    "color": "orange",+                    "offset": 0.4+                },+                {+                    "color": "blue",+                    "offset": 1+                }+            ],+            "gradient": "linear",+            "y2": 1,+            "x1": 1+        },+        "type": "bar"+    },+    "data": {+        "values": [+            {+                "value": 10,+                "cat": "a"+            },+            {+                "value": 5,+                "cat": "b"+            },+            {+                "value": 20,+                "cat": "c"+            },+            {+                "value": 8,+                "cat": "d"+            }+        ]+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "type": "nominal"+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/gradient2.vl view
@@ -0,0 +1,54 @@+{+    "mark": {+        "color": {+            "x2": 1,+            "y1": 1,+            "stops": [+                {+                    "color": "red",+                    "offset": 0+                },+                {+                    "color": "blue",+                    "offset": 1+                }+            ],+            "gradient": "linear",+            "y2": 1,+            "x1": 0+        },+        "type": "bar"+    },+    "data": {+        "values": [+            {+                "value": 10,+                "cat": "a"+            },+            {+                "value": 5,+                "cat": "b"+            },+            {+                "value": 20,+                "cat": "c"+            },+            {+                "value": 8,+                "cat": "d"+            }+        ]+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "type": "nominal"+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/gradient3.vl view
@@ -0,0 +1,54 @@+{+    "mark": {+        "color": {+            "x2": 1,+            "y1": 0,+            "stops": [+                {+                    "color": "blue",+                    "offset": 0+                },+                {+                    "color": "red",+                    "offset": 1+                }+            ],+            "gradient": "linear",+            "y2": 1,+            "x1": 0+        },+        "type": "bar"+    },+    "data": {+        "values": [+            {+                "value": 10,+                "cat": "a"+            },+            {+                "value": 5,+                "cat": "b"+            },+            {+                "value": 20,+                "cat": "c"+            },+            {+                "value": 8,+                "cat": "d"+            }+        ]+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "type": "nominal"+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/gradientr1.vl view
@@ -0,0 +1,55 @@+{+    "mark": {+        "color": {+            "stops": [+                {+                    "color": "red",+                    "offset": 0+                },+                {+                    "color": "white",+                    "offset": 0.5+                },+                {+                    "color": "blue",+                    "offset": 1+                }+            ],+            "gradient": "radial"+        },+        "size": 1000,+        "type": "circle"+    },+    "data": {+        "values": [+            {+                "value": 10,+                "cat": "a"+            },+            {+                "value": 5,+                "cat": "b"+            },+            {+                "value": 20,+                "cat": "c"+            },+            {+                "value": 8,+                "cat": "d"+            }+        ]+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "type": "nominal"+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/gradientr2.vl view
@@ -0,0 +1,59 @@+{+    "mark": {+        "color": {+            "x2": 0.5,+            "y1": 0.5,+            "stops": [+                {+                    "color": "red",+                    "offset": 0+                },+                {+                    "color": "white",+                    "offset": 0.5+                },+                {+                    "color": "blue",+                    "offset": 1+                }+            ],+            "gradient": "radial",+            "y2": 0.5,+            "x1": 0.5+        },+        "size": 1000,+        "type": "circle"+    },+    "data": {+        "values": [+            {+                "value": 10,+                "cat": "a"+            },+            {+                "value": 5,+                "cat": "b"+            },+            {+                "value": 20,+                "cat": "c"+            },+            {+                "value": 8,+                "cat": "d"+            }+        ]+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "type": "nominal"+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
+ tests/specs/fillstroke/gradientr3.vl view
@@ -0,0 +1,61 @@+{+    "mark": {+        "color": {+            "x2": 0.8,+            "y1": 0.7,+            "r2": 0.4,+            "stops": [+                {+                    "color": "red",+                    "offset": 0+                },+                {+                    "color": "white",+                    "offset": 0.5+                },+                {+                    "color": "blue",+                    "offset": 1+                }+            ],+            "gradient": "radial",+            "y2": 0.3,+            "r1": 0.2,+            "x1": 0.2+        },+        "size": 1000,+        "type": "circle"+    },+    "data": {+        "values": [+            {+                "value": 10,+                "cat": "a"+            },+            {+                "value": 5,+                "cat": "b"+            },+            {+                "value": 20,+                "cat": "c"+            },+            {+                "value": 8,+                "cat": "d"+            }+        ]+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "cat",+            "type": "nominal"+        },+        "y": {+            "field": "value",+            "type": "quantitative"+        }+    }+}
tests/specs/fillstroke/stroke1.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/stroke2.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/fillstroke/stroke3.vl view
@@ -33,7 +33,7 @@         ]     },     "width": 200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "cat",
tests/specs/gallery/advanced/advanced1.vl view
@@ -18,6 +18,9 @@             "calculate": "datum.Time/datum.TotalTime * 100"         }     ],+    "height": {+        "step": 12+    },     "mark": "bar",     "data": {         "values": [@@ -43,7 +46,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "PercentOfTotal",@@ -54,9 +57,6 @@         },         "y": {             "field": "Activity",-            "scale": {-                "rangeStep": 12-            },             "type": "nominal"         }     },
tests/specs/gallery/advanced/advanced2.vl view
@@ -23,7 +23,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar",
tests/specs/gallery/advanced/advanced3.vl view
@@ -36,7 +36,7 @@             }         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/advanced/advanced4.vl view
@@ -40,7 +40,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Release_Date",
tests/specs/gallery/advanced/advanced5.vl view
@@ -102,7 +102,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "title": {         "fontStyle": "italic",         "text": "World Cup 2018: Group F Rankings",
tests/specs/gallery/advanced/advanced6.vl view
@@ -109,7 +109,7 @@         ]     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/advanced/advanced7.vl view
@@ -18,7 +18,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/lookup_groups.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "group",
tests/specs/gallery/advanced/advanced8.vl view
@@ -69,7 +69,7 @@         "url": "https://vega.github.io/vega-lite/data/iris.json"     },     "width": 600,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/advanced/advanced9.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Production_Budget",
+ tests/specs/gallery/advanced/benchmark.vl view
@@ -0,0 +1,517 @@+{+    "height": 300,+    "width": 500,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "transform": [+                {+                    "window": [+                        {+                            "op": "row_number",+                            "as": "row"+                        }+                    ]+                },+                {+                    "as": "fps",+                    "calculate": "1000/datum.data"+                },+                {+                    "as": "system",+                    "calculate": "'Falcon'"+                }+            ],+            "mark": "line",+            "data": {+                "name": "falcon"+            }+        },+        {+            "transform": [+                {+                    "window": [+                        {+                            "op": "row_number",+                            "as": "row"+                        }+                    ]+                },+                {+                    "as": "fps",+                    "calculate": "1000/datum.data"+                },+                {+                    "as": "system",+                    "calculate": "'Square Crossfilter (3M)'"+                }+            ],+            "mark": "line",+            "data": {+                "name": "square"+            }+        }+    ],+    "encoding": {+        "color": {+            "field": "system",+            "type": "nominal",+            "legend": {+                "orient": "bottom-right",+                "title": "System"+            }+        },+        "size": {+            "value": 1+        },+        "x": {+            "field": "row",+            "scale": {+                "nice": false+            },+            "type": "quantitative",+            "axis": {+                "grid": false,+                "title": "Trial"+            }+        },+        "y": {+            "field": "fps",+            "scale": {+                "type": "log"+            },+            "type": "quantitative",+            "axis": {+                "grid": false,+                "title": "Frames per Second (fps)"+            }+        }+    },+    "description": "Line chart to show benchmarking results.",+    "datasets": {+        "square": [+            24.200000762939453,+            17.899999618530273,+            15.800000190734863,+            58.400001525878906,+            151,+            2523.10009765625,+            245.3000030517578,+            136,+            72.30000305175781,+            55.70000076293945,+            42.400001525878906,+            37.70000076293945,+            30.100000381469727,+            30.100000381469727,+            21.799999237060547,+            20.600000381469727,+            21.799999237060547,+            17.600000381469727,+            18.200000762939453,+            21,+            941.7000122070313,+            177.39999389648438,+            2821.800048828125,+            359.20001220703125,+            318,+            217.10000610351563,+            126,+            69,+            57.79999923706055,+            45.29999923706055,+            35.599998474121094,+            29.100000381469727,+            23.799999237060547,+            44.20000076293945,+            17.700000762939453,+            17.700000762939453,+            15.699999809265137,+            27.799999237060547,+            22.799999237060547,+            3853.60009765625,+            91.5999984741211,+            181.39999389648438,+            476.29998779296875,+            265.8999938964844,+            254.60000610351563,+            2583.199951171875,+            124.80000305175781,+            73.19999694824219,+            56.400001525878906,+            48.70000076293945,+            41.599998474121094,+            21.100000381469727,+            20.299999237060547,+            21.299999237060547,+            18.299999237060547,+            17.100000381469727,+            19.5,+            828.2000122070313,+            162.1999969482422,+            217.89999389648438,+            205.5,+            197.60000610351563,+            2249.800048828125,+            103.0999984741211,+            71.69999694824219,+            57.599998474121094,+            41.400001525878906,+            34.5,+            22,+            20.5,+            21.700000762939453,+            18.299999237060547,+            17.299999237060547,+            19.399999618530273,+            666.7999877929688,+            214.89999389648438,+            212.3000030517578,+            125.80000305175781,+            67.69999694824219,+            56.099998474121094,+            45.79999923706055,+            38.29999923706055,+            33,+            35.400001525878906,+            22.700000762939453,+            19.399999618530273,+            19.899999618530273,+            24.100000381469727,+            19.299999237060547,+            21.299999237060547,+            3508.699951171875,+            204.10000610351563,+            125.4000015258789,+            65.30000305175781,+            60.79999923706055,+            44.099998474121094,+            36.29999923706055,+            30.5,+            28.600000381469727,+            16.5,+            18.600000381469727,+            23.700000762939453,+            22.299999237060547,+            17.600000381469727,+            19.200000762939453,+            448.79998779296875,+            124.4000015258789,+            66.5999984741211,+            53.5,+            51,+            45.20000076293945,+            28.399999618530273,+            29.200000762939453,+            26.700000762939453,+            25.899999618530273,+            18.100000381469727,+            17.600000381469727,+            20.100000381469727,+            25.200000762939453,+            3332,+            67.5,+            53.599998474121094,+            56.599998474121094,+            39.900001525878906,+            27.600000381469727,+            29.600000381469727,+            33.5,+            17.200000762939453,+            18.799999237060547,+            25.200000762939453,+            16.700000762939453,+            16.899999618530273,+            240.1999969482422,+            52.400001525878906,+            42.099998474121094,+            33.900001525878906,+            28,+            28.600000381469727,+            17.299999237060547,+            20,+            21,+            22.799999237060547,+            16.700000762939453,+            19.200000762939453,+            175.39999389648438,+            43.5,+            34.70000076293945,+            29.700000762939453,+            34.900001525878906,+            25.799999237060547,+            17.299999237060547,+            22.600000381469727,+            17.600000381469727,+            17.200000762939453,+            19.200000762939453,+            111.80000305175781,+            35.400001525878906,+            27.600000381469727,+            25.399999618530273,+            21.899999618530273,+            18.600000381469727,+            18.100000381469727,+            21.200000762939453,+            17.899999618530273,+            17,+            80.5999984741211,+            29.799999237060547,+            30.100000381469727,+            16,+            26.799999237060547,+            17.5,+            22.299999237060547,+            16.799999237060547,+            22.399999618530273,+            77.4000015258789,+            31,+            29.700000762939453,+            28.700000762939453,+            26,+            16.899999618530273,+            15.800000190734863,+            19,+            52.599998474121094,+            25.200000762939453,+            16.700000762939453,+            17.899999618530273,+            21,+            19.799999237060547,+            18.799999237060547,+            46.5,+            17.5,+            16.799999237060547,+            18.299999237060547,+            18.299999237060547,+            14.899999618530273,+            41,+            18.299999237060547,+            17.299999237060547,+            17,+            17.5,+            32.29999923706055,+            22.600000381469727,+            16.600000381469727,+            17.899999618530273,+            25.600000381469727,+            17.5,+            20.299999237060547,+            25.200000762939453,+            18.600000381469727,+            17.700000762939453+        ],+        "falcon": [+            16.81999969482422,+            19.759998321533203,+            16.079999923706055,+            19.579999923706055,+            16.420000076293945,+            16.200000762939453,+            16.020000457763672,+            15.9399995803833,+            16.280000686645508,+            16.119998931884766,+            16.15999984741211,+            16.119998931884766,+            16.139999389648438,+            16.100000381469727,+            16.200000762939453,+            16.260000228881836,+            19.35999870300293,+            19.700000762939453,+            15.9399995803833,+            19.139999389648438,+            16.200000762939453,+            16.119998931884766,+            19.520000457763672,+            19.700000762939453,+            16.200000762939453,+            20.979999542236328,+            16.299999237060547,+            16.420000076293945,+            16.81999969482422,+            16.5,+            16.560001373291016,+            16.18000030517578,+            16.079999923706055,+            16.239999771118164,+            16.040000915527344,+            16.299999237060547,+            19.399999618530273,+            15.699999809265137,+            16.239999771118164,+            15.920000076293945,+            16.259998321533203,+            16.219999313354492,+            16.520000457763672,+            16.459999084472656,+            16.360000610351563,+            15.719999313354492,+            16.060001373291016,+            15.960000991821289,+            16.479999542236328,+            16.600000381469727,+            16.240001678466797,+            16.940000534057617,+            16.220001220703125,+            15.959999084472656,+            15.899999618530273,+            16.479999542236328,+            16.31999969482422,+            15.75999927520752,+            15.999998092651367,+            16.18000030517578,+            16.219999313354492,+            15.800000190734863,+            16.139999389648438,+            16.299999237060547,+            16.360000610351563,+            16.260000228881836,+            15.959999084472656,+            15.9399995803833,+            16.53999900817871,+            16.139999389648438,+            16.259998321533203,+            16.200000762939453,+            15.899999618530273,+            16.079999923706055,+            16.079999923706055,+            15.699999809265137,+            15.660000801086426,+            16.139999389648438,+            23.100000381469727,+            16.600000381469727,+            16.420000076293945,+            16.020000457763672,+            15.619999885559082,+            16.35999870300293,+            15.719999313354492,+            15.920001029968262,+            15.5600004196167,+            16.34000015258789,+            22.82000160217285,+            15.660000801086426,+            15.5600004196167,+            16,+            16,+            15.819999694824219,+            16.399999618530273,+            16.46000099182129,+            16.059999465942383,+            16.239999771118164,+            15.800000190734863,+            16.15999984741211,+            16.360000610351563,+            19.700000762939453,+            16.10000228881836,+            16.139999389648438,+            15.819999694824219,+            16.439998626708984,+            16.139999389648438,+            16.020000457763672,+            15.860000610351563,+            16.059999465942383,+            16.020000457763672,+            15.920000076293945,+            15.819999694824219,+            16.579999923706055,+            15.880000114440918,+            16.579999923706055,+            15.699999809265137,+            19.380001068115234,+            19.239999771118164,+            16,+            15.980000495910645,+            15.959999084472656,+            16.200000762939453,+            15.980000495910645,+            16.34000015258789,+            16.31999969482422,+            16.260000228881836,+            15.920000076293945,+            15.540000915527344,+            16.139999389648438,+            16.459999084472656,+            16.34000015258789,+            15.819999694824219,+            19.719999313354492,+            15.75999927520752,+            16.499998092651367,+            15.719999313354492,+            16.079999923706055,+            16.439998626708984,+            16.200000762939453,+            15.959999084472656,+            16,+            16.100000381469727,+            19.31999969482422,+            16.100000381469727,+            16.18000030517578,+            15.959999084472656,+            22.639999389648438,+            15.899999618530273,+            16.279998779296875,+            16.100000381469727,+            15.920000076293945,+            16.079999923706055,+            16.260000228881836,+            15.899999618530273,+            15.820001602172852,+            15.699999809265137,+            15.979998588562012,+            16.380001068115234,+            16.040000915527344,+            19.420000076293945,+            15.9399995803833,+            16.15999984741211,+            15.960000991821289,+            16.259998321533203,+            15.780000686645508,+            15.880000114440918,+            15.980000495910645,+            16.060001373291016,+            16.119998931884766,+            23.020000457763672,+            15.619999885559082,+            15.920000076293945,+            16.060001373291016,+            14.780000686645508,+            16.260000228881836,+            19.520000457763672,+            16.31999969482422,+            16.600000381469727,+            16.219999313354492,+            19.740001678466797,+            19.46000099182129,+            15.940000534057617,+            15.839999198913574,+            16.100000381469727,+            16.46000099182129,+            16.17999839782715,+            16.100000381469727,+            15.9399995803833,+            16.060001373291016,+            15.860000610351563,+            15.819999694824219,+            16.03999900817871,+            16.17999839782715,+            15.819999694824219,+            17.299999237060547,+            15.9399995803833,+            15.739999771118164,+            15.719999313354492,+            15.679998397827148,+            15.619999885559082,+            15.600000381469727,+            16.03999900817871,+            15.5,+            15.600001335144043,+            19.439998626708984,+            15.960000991821289,+            16.239999771118164,+            16.040000915527344,+            16.239999771118164+        ]+    }+}
+ tests/specs/gallery/advanced/density1.vl view
@@ -0,0 +1,45 @@+{+    "transform": [+        {+            "as": [+                "organ",+                "value"+            ],+            "fold": [+                "petalWidth",+                "petalLength",+                "sepalWidth",+                "sepalLength"+            ]+        },+        {+            "groupby": [+                "organ"+            ],+            "bandwidth": 0.3,+            "density": "value"+        }+    ],+    "height": 50,+    "mark": "area",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/iris.json"+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "row": {+            "field": "organ",+            "type": "nominal"+        },+        "x": {+            "field": "value",+            "title": "value (cm)",+            "type": "quantitative"+        },+        "y": {+            "field": "density",+            "type": "quantitative"+        }+    }+}
+ tests/specs/gallery/advanced/density2.vl view
@@ -0,0 +1,53 @@+{+    "transform": [+        {+            "as": [+                "measurement",+                "value"+            ],+            "fold": [+                "petalWidth",+                "petalLength",+                "sepalWidth",+                "sepalLength"+            ]+        },+        {+            "groupby": [+                "measurement"+            ],+            "extent": [+                0,+                8+            ],+            "steps": 200,+            "bandwidth": 0.3,+            "density": "value"+        }+    ],+    "height": 100,+    "mark": {+        "opacity": 0.5,+        "type": "area"+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/iris.json"+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "measurement",+            "type": "nominal"+        },+        "x": {+            "field": "value",+            "title": "width/length (cm)",+            "type": "quantitative"+        },+        "y": {+            "field": "density",+            "type": "quantitative"+        }+    }+}
+ tests/specs/gallery/advanced/filter1.vl view
@@ -0,0 +1,130 @@+{+    "transform": [+        {+            "window": [+                {+                    "op": "rank",+                    "as": "rank"+                }+            ],+            "sort": [+                {+                    "field": "score",+                    "order": "descending"+                }+            ]+        },+        {+            "filter": "datum.rank <=5"+        }+    ],+    "mark": "bar",+    "data": {+        "values": [+            {+                "score": 100,+                "student": "A"+            },+            {+                "score": 56,+                "student": "B"+            },+            {+                "score": 88,+                "student": "C"+            },+            {+                "score": 65,+                "student": "D"+            },+            {+                "score": 45,+                "student": "E"+            },+            {+                "score": 23,+                "student": "F"+            },+            {+                "score": 66,+                "student": "G"+            },+            {+                "score": 67,+                "student": "H"+            },+            {+                "score": 13,+                "student": "I"+            },+            {+                "score": 12,+                "student": "J"+            },+            {+                "score": 50,+                "student": "K"+            },+            {+                "score": 78,+                "student": "L"+            },+            {+                "score": 66,+                "student": "M"+            },+            {+                "score": 30,+                "student": "N"+            },+            {+                "score": 97,+                "student": "O"+            },+            {+                "score": 75,+                "student": "P"+            },+            {+                "score": 24,+                "student": "Q"+            },+            {+                "score": 42,+                "student": "R"+            },+            {+                "score": 76,+                "student": "S"+            },+            {+                "score": 78,+                "student": "T"+            },+            {+                "score": 21,+                "student": "U"+            },+            {+                "score": 46,+                "student": "V"+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "score",+            "type": "quantitative"+        },+        "y": {+            "field": "student",+            "sort": {+                "encoding": "x",+                "order": "descending"+            },+            "type": "nominal"+        }+    },+    "description": "Filtering the top-k items"+}
+ tests/specs/gallery/advanced/filter2.vl view
@@ -0,0 +1,58 @@+{+    "transform": [+        {+            "groupby": [+                "Director"+            ],+            "aggregate": [+                {+                    "op": "mean",+                    "as": "aggregateGross",+                    "field": "Worldwide_Gross"+                }+            ]+        },+        {+            "window": [+                {+                    "op": "row_number",+                    "as": "rank"+                }+            ],+            "sort": [+                {+                    "field": "aggregateGross",+                    "order": "descending"+                }+            ]+        },+        {+            "as": "rankedDirector",+            "calculate": "datum.rank < 10 ? datum.Director : 'All Others'"+        }+    ],+    "mark": "bar",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "title": "Top Directors by Average Worldwide Gross",+    "encoding": {+        "x": {+            "field": "aggregateGross",+            "aggregate": "mean",+            "title": null,+            "type": "quantitative"+        },+        "y": {+            "field": "rankedDirector",+            "sort": {+                "encoding": "x",+                "order": "descending"+            },+            "title": null,+            "type": "ordinal"+        }+    },+    "description": "Top-k items with 'others'"+}
+ tests/specs/gallery/advanced/layered1.vl view
@@ -0,0 +1,85 @@+{+    "transform": [+        {+            "as": "binIMDB_Rating",+            "field": "IMDB_Rating",+            "bin": true+        },+        {+            "groupby": [+                "binIMDB_Rating",+                "binIMDB_Rating_end"+            ],+            "aggregate": [+                {+                    "op": "count",+                    "as": "count"+                }+            ]+        },+        {+            "filter": "datum.binIMDB_Rating !== null"+        },+        {+            "window": [+                {+                    "op": "sum",+                    "as": "cumulativeCount",+                    "field": "count"+                }+            ],+            "sort": [+                {+                    "field": "binIMDB_Rating",+                    "order": "ascending"+                }+            ],+            "frame": [+                null,+                0+            ]+        }+    ],+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": "bar",+            "encoding": {+                "y": {+                    "field": "cumulativeCount",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "yellow",+                "opacity": 0.5,+                "type": "bar"+            },+            "encoding": {+                "y": {+                    "field": "count",+                    "type": "quantitative"+                }+            }+        }+    ],+    "encoding": {+        "x2": {+            "field": "binIMDB_Rating_end"+        },+        "x": {+            "field": "binIMDB_Rating",+            "scale": {+                "zero": false+            },+            "title": "IMDB Rating",+            "type": "quantitative"+        }+    },+    "description": "Layered Histogram and Cumulative Histogram"+}
+ tests/specs/gallery/advanced/layered2.vl view
@@ -0,0 +1,46 @@+{+    "transform": [+        {+            "filter": "datum.symbol === 'GOOG'"+        }+    ],+    "data": {+        "url": "https://vega.github.io/vega-lite/data/stocks.csv"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "opacity": 0.3,+                "type": "point"+            },+            "encoding": {+                "x": {+                    "field": "date",+                    "timeUnit": "year",+                    "type": "temporal"+                },+                "y": {+                    "field": "price",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": "line",+            "encoding": {+                "x": {+                    "field": "date",+                    "timeUnit": "year",+                    "type": "temporal"+                },+                "y": {+                    "field": "price",+                    "aggregate": "mean",+                    "type": "quantitative"+                }+            }+        }+    ],+    "description": "Plot showing average data with raw values in the background."+}
+ tests/specs/gallery/advanced/layered3.vl view
@@ -0,0 +1,61 @@+{+    "transform": [+        {+            "window": [+                {+                    "op": "mean",+                    "as": "rollingMean",+                    "field": "temp_max"+                }+            ],+            "frame": [+                -15,+                15+            ]+        }+    ],+    "height": 300,+    "data": {+        "url": "https://vega.github.io/vega-lite/data/seattle-weather.csv"+    },+    "width": 400,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "opacity": 0.3,+                "type": "point"+            },+            "encoding": {+                "x": {+                    "field": "date",+                    "title": "Date",+                    "type": "temporal"+                },+                "y": {+                    "field": "temp_max",+                    "title": "Maximum temperature",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 3,+                "type": "line"+            },+            "encoding": {+                "x": {+                    "field": "date",+                    "type": "temporal"+                },+                "y": {+                    "field": "rollingMean",+                    "type": "quantitative"+                }+            }+        }+    ],+    "description": "Plot showing a 30 day rolling average with raw values in the background."+}
+ tests/specs/gallery/advanced/transform1.vl view
@@ -0,0 +1,87 @@+{+    "transform": [+        {+            "window": [+                {+                    "op": "count",+                    "as": "cumulativeCount"+                }+            ],+            "sort": [+                {+                    "field": "NOX",+                    "order": "ascending"+                }+            ]+        }+    ],+    "mark": {+        "strokeWidth": 2,+        "stroke": {+            "stops": [+                {+                    "color": "orange",+                    "offset": 0+                },+                {+                    "color": "green",+                    "offset": 0.5+                },+                {+                    "color": "purple",+                    "offset": 1+                }+            ],+            "gradient": "linear"+        },+        "fill": {+            "x2": 1,+            "y1": 1,+            "stops": [+                {+                    "color": "white",+                    "offset": 0+                },+                {+                    "color": "black",+                    "offset": 1+                }+            ],+            "gradient": "linear",+            "y2": 1,+            "x1": 0+        },+        "strokeDashOffset": 5,+        "strokeDash": [+            10,+            6,+            6,+            6+        ],+        "strokeOpacity": 0.8,+        "type": "area",+        "fillOpacity": 0.5+    },+    "data": {+        "url": "https://gicentre.github.io/data/putneyAirQuality2018.csv",+        "format": {+            "parse": {+                "NOX": "number"+            }+        }+    },+    "width": 500,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "NOX",+            "title": "NOX concentration (μg/㎥)",+            "type": "quantitative"+        },+        "y": {+            "field": "cumulativeCount",+            "type": "quantitative"+        }+    },+    "description": "Cumulative Frequency Distribution"+}
tests/specs/gallery/area/area1.vl view
@@ -5,7 +5,7 @@         "url": "https://vega.github.io/vega-lite/data/unemployment-across-industries.json"     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
tests/specs/gallery/area/area2.vl view
@@ -12,7 +12,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/stocks.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
tests/specs/gallery/area/area3.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/unemployment-across-industries.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "series",
tests/specs/gallery/area/area4.vl view
@@ -5,7 +5,7 @@         "url": "https://vega.github.io/vega-lite/data/unemployment-across-industries.json"     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "series",
tests/specs/gallery/area/area5.vl view
@@ -5,7 +5,7 @@         "url": "https://vega.github.io/vega-lite/data/unemployment-across-industries.json"     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "series",
tests/specs/gallery/area/area6.vl view
@@ -91,7 +91,7 @@         ]     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/area/area7.vl view
@@ -243,5 +243,5 @@             ]         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
+ tests/specs/gallery/bar/agesorted.vl view
@@ -0,0 +1,34 @@+{+    "transform": [+        {+            "filter": "datum.year == 2000"+        }+    ],+    "height": {+        "step": 17+    },+    "mark": "bar",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "people",+            "aggregate": "sum",+            "type": "quantitative",+            "axis": {+                "title": "population"+            }+        },+        "y": {+            "field": "age",+            "sort": {+                "encoding": "x",+                "order": "descending"+            },+            "type": "ordinal"+        }+    },+    "description": "A bar chart showing the US population distribution of age groups in 2000, sorted by population"+}
tests/specs/gallery/bar/bar1.vl view
@@ -40,7 +40,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "a",
tests/specs/gallery/bar/bar10.vl view
@@ -12,7 +12,10 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "width": {+        "step": 17+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "gender",@@ -29,9 +32,6 @@         },         "x": {             "field": "age",-            "scale": {-                "rangeStep": 17-            },             "type": "ordinal"         },         "y": {
tests/specs/gallery/bar/bar11.vl view
@@ -324,7 +324,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x2": {             "field": "percentage_end"
tests/specs/gallery/bar/bar12.vl view
@@ -24,7 +24,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar"
tests/specs/gallery/bar/bar13.vl view
@@ -199,7 +199,7 @@         ]     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "animal",
tests/specs/gallery/bar/bar14.vl view
@@ -217,7 +217,7 @@         ]     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "size": {             "value": 65
tests/specs/gallery/bar/bar2.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "IMDB_Rating",
tests/specs/gallery/bar/bar3.vl view
@@ -4,11 +4,14 @@             "filter": "datum.year == 2000"         }     ],+    "height": {+        "step": 17+    },     "mark": "bar",     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "people",@@ -20,9 +23,6 @@         },         "y": {             "field": "age",-            "scale": {-                "rangeStep": 17-            },             "sort": "descending",             "type": "ordinal"         }
tests/specs/gallery/bar/bar4.vl view
@@ -20,7 +20,10 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "width": {+        "step": 12+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "gender",@@ -34,9 +37,6 @@         },         "x": {             "field": "gender",-            "scale": {-                "rangeStep": 12-            },             "type": "nominal",             "axis": {                 "title": null
tests/specs/gallery/bar/bar5.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/seattle-weather.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "weather",
tests/specs/gallery/bar/bar6.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "site",
tests/specs/gallery/bar/bar7.vl view
@@ -12,7 +12,10 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "width": {+        "step": 17+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "gender",@@ -26,9 +29,6 @@         },         "x": {             "field": "age",-            "scale": {-                "rangeStep": 17-            },             "type": "ordinal"         },         "y": {
tests/specs/gallery/bar/bar8.vl view
@@ -19,7 +19,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x2": {             "field": "end"
tests/specs/gallery/bar/bar9.vl view
@@ -16,7 +16,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "color",
+ tests/specs/gallery/bar/explicitbins.vl view
@@ -0,0 +1,64 @@+{+    "mark": "bar",+    "data": {+        "values": [+            {+                "binEnd": 10,+                "count": 7,+                "binStart": 8+            },+            {+                "binEnd": 12,+                "count": 29,+                "binStart": 10+            },+            {+                "binEnd": 14,+                "count": 71,+                "binStart": 12+            },+            {+                "binEnd": 16,+                "count": 127,+                "binStart": 14+            },+            {+                "binEnd": 18,+                "count": 94,+                "binStart": 16+            },+            {+                "binEnd": 20,+                "count": 54,+                "binStart": 18+            },+            {+                "binEnd": 22,+                "count": 17,+                "binStart": 20+            },+            {+                "binEnd": 24,+                "count": 5,+                "binStart": 22+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x2": {+            "field": "binEnd"+        },+        "x": {+            "field": "binStart",+            "bin": {+                "step": 2+            },+            "type": "quantitative"+        },+        "y": {+            "field": "count",+            "type": "quantitative"+        }+    }+}
+ tests/specs/gallery/bar/labeloverlay.vl view
@@ -0,0 +1,78 @@+{+    "transform": [+        {+            "as": "genre",+            "calculate": "isValid(datum.Major_Genre)? datum.Major_Genre : 'unclassified'"+        }+    ],+    "height": {+        "step": 16+    },+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "width": 200,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "color": "#ddd",+                "type": "bar"+            },+            "encoding": {+                "x": {+                    "field": "IMDB_Rating",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "aggregate": "mean",+                    "title": "Mean IMDB Ratings",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "dx": 5,+                "align": "center",+                "type": "text"+            },+            "encoding": {+                "text": {+                    "field": "genre",+                    "type": "nominal"+                },+                "detail": {+                    "aggregate": "count",+                    "type": "quantitative"+                }+            }+        }+    ],+    "encoding": {+        "y": {+            "field": "genre",+            "sort": [+                "Action",+                "Adventure",+                "Comedy",+                "Black Comedy",+                "Romantic Comedy",+                "Concert/Performance",+                "Documentary",+                "Drama",+                "Horror",+                "Musical",+                "Thriller/Suspense",+                "Western",+                "unclassified"+            ],+            "type": "nominal",+            "axis": null+        }+    },+    "description": "Bar chart with label overlay"+}
+ tests/specs/gallery/bar/logscaled.vl view
@@ -0,0 +1,81 @@+{+    "transform": [+        {+            "as": "logX",+            "calculate": "log(datum.x)/log(10)"+        },+        {+            "as": "binLogX",+            "field": "logX",+            "bin": true+        },+        {+            "as": "x1",+            "calculate": "pow(10,datum.binLogX)"+        },+        {+            "as": "x2",+            "calculate": "pow(10,datum.binLogX_end)"+        }+    ],+    "mark": "bar",+    "data": {+        "values": [+            {+                "x": 1.0e-2+            },+            {+                "x": 0.1+            },+            {+                "x": 1+            },+            {+                "x": 1+            },+            {+                "x": 1+            },+            {+                "x": 1+            },+            {+                "x": 10+            },+            {+                "x": 10+            },+            {+                "x": 100+            },+            {+                "x": 500+            },+            {+                "x": 800+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x2": {+            "field": "x2"+        },+        "x": {+            "field": "x1",+            "scale": {+                "base": 10,+                "type": "log"+            },+            "type": "quantitative",+            "axis": {+                "tickCount": 5+            }+        },+        "y": {+            "aggregate": "count",+            "type": "quantitative"+        }+    },+    "description": "Log-scaled Histogram (may improve after https://github.com/vega/vega-lite/issues/4792)"+}
+ tests/specs/gallery/bar/signedpopulation.vl view
@@ -0,0 +1,61 @@+{+    "transform": [+        {+            "filter": "datum.year == 2000"+        },+        {+            "as": "gender",+            "calculate": "datum.sex == 2 ? 'Female' : 'Male'"+        },+        {+            "as": "signedPeople",+            "calculate": "datum.sex == 2 ? datum.people : -datum.people"+        }+    ],+    "height": 200,+    "config": {+        "view": {+            "stroke": null+        },+        "axis": {+            "grid": false+        }+    },+    "mark": "bar",+    "data": {+        "url": "https://vega.github.io/vega-lite/data/population.json"+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "color": {+            "field": "gender",+            "scale": {+                "range": [+                    "#675193",+                    "#ca8861"+                ]+            },+            "type": "nominal",+            "legend": {+                "orient": "top",+                "title": ""+            }+        },+        "x": {+            "field": "signedPeople",+            "aggregate": "sum",+            "type": "quantitative",+            "axis": {+                "format": "s",+                "title": "Population"+            }+        },+        "y": {+            "field": "age",+            "sort": "descending",+            "type": "ordinal",+            "axis": null+        }+    }+}
+ tests/specs/gallery/bar/wilkinsondotplot.vl view
@@ -0,0 +1,107 @@+{+    "transform": [+        {+            "window": [+                {+                    "op": "rank",+                    "as": "id",+                    "field": "rank"+                }+            ],+            "groupby": [+                "data"+            ]+        }+    ],+    "height": 100,+    "config": {+        "view": {+            "stroke": null+        }+    },+    "mark": {+        "opacity": 1,+        "type": "circle"+    },+    "data": {+        "values": [+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 1+            },+            {+                "data": 2+            },+            {+                "data": 2+            },+            {+                "data": 2+            },+            {+                "data": 3+            },+            {+                "data": 3+            },+            {+                "data": 4+            },+            {+                "data": 4+            },+            {+                "data": 4+            },+            {+                "data": 4+            },+            {+                "data": 4+            },+            {+                "data": 4+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "x": {+            "field": "data",+            "type": "ordinal"+        },+        "y": {+            "field": "id",+            "sort": "descending",+            "type": "ordinal",+            "axis": null+        }+    },+    "description": "A Wilkinson dot plot"+}
tests/specs/gallery/dist/dist1.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "IMDB_Rating",
tests/specs/gallery/dist/dist2.vl view
@@ -24,7 +24,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "IMDB_Rating",
tests/specs/gallery/dist/dist3.vl view
@@ -43,7 +43,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar",
tests/specs/gallery/dist/dist4.vl view
@@ -36,7 +36,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/dist/dist5.vl view
@@ -38,7 +38,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
+ tests/specs/gallery/dist/quantile1.vl view
@@ -0,0 +1,52 @@+{+    "transform": [+        {+            "as": [+                "p",+                "v"+            ],+            "quantile": "u",+            "step": 1.0e-2+        },+        {+            "as": "unif",+            "calculate": "quantileUniform(datum.p)"+        },+        {+            "as": "norm",+            "calculate": "quantileNormal(datum.p)"+        }+    ],+    "hconcat": [+        {+            "mark": "point",+            "encoding": {+                "x": {+                    "field": "unif",+                    "type": "quantitative"+                },+                "y": {+                    "field": "v",+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": "point",+            "encoding": {+                "x": {+                    "field": "norm",+                    "type": "quantitative"+                },+                "y": {+                    "field": "v",+                    "type": "quantitative"+                }+            }+        }+    ],+    "data": {+        "url": "https://vega.github.io/vega-lite/data/normal-2d.json"+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json"+}
tests/specs/gallery/error/error1.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/error/error2.vl view
@@ -29,7 +29,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/error/error3.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "area",
tests/specs/gallery/error/error4.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "point",
tests/specs/gallery/facet/facet1.vl view
@@ -12,7 +12,10 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/population.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "width": {+        "step": 17+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "gender",@@ -30,9 +33,6 @@         },         "x": {             "field": "age",-            "scale": {-                "rangeStep": 17-            },             "type": "ordinal"         },         "y": {
tests/specs/gallery/facet/facet2.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "site",
tests/specs/gallery/facet/facet3.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Worldwide_Gross",
tests/specs/gallery/facet/facet4.vl view
@@ -3,10 +3,11 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "row": {             "field": "Origin",+            "title": "Origin facet",             "type": "ordinal"         },         "x": {@@ -21,5 +22,5 @@             "type": "quantitative"         }     },-    "description": "Disitributions of car engine power for different countries of origin"+    "description": "Distributions of car engine power for different countries of origin" }
tests/specs/gallery/facet/facet5.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/anscombe.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "opacity": {             "value": 1
tests/specs/gallery/facet/facet6.vl view
@@ -3,6 +3,9 @@         "url": "https://vega.github.io/vega-lite/data/barley.json"     },     "spec": {+        "height": {+            "step": 12+        },         "mark": "point",         "encoding": {             "color": {@@ -19,9 +22,6 @@             },             "y": {                 "field": "variety",-                "scale": {-                    "rangeStep": 12-                },                 "sort": {                     "encoding": "x",                     "order": "descending"@@ -30,7 +30,7 @@             }         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "columns": 2,     "facet": {         "field": "site",
tests/specs/gallery/facet/facet7.vl view
@@ -15,7 +15,7 @@             "y": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "symbol",@@ -26,7 +26,8 @@             "field": "symbol",             "header": {                 "labelAngle": 0,-                "title": "Stock price"+                "title": "Stock price",+                "labelAlign": "left"             },             "type": "nominal"         },
tests/specs/gallery/geo/geo1.vl view
@@ -28,7 +28,7 @@         }     },     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/gallery/geo/geo2.vl view
@@ -16,7 +16,7 @@         "url": "https://vega.github.io/vega-lite/data/zipcodes.csv"     },     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/gallery/geo/geo3.vl view
@@ -6,7 +6,7 @@         }     },     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/gallery/geo/geo4.vl view
@@ -6,7 +6,7 @@         }     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },@@ -57,46 +57,24 @@                     }                 },                 {+                    "as": "o",                     "from": {                         "data": {                             "url": "https://vega.github.io/vega-lite/data/airports.csv"                         },-                        "key": "iata",-                        "fields": [-                            "latitude",-                            "longitude"-                        ]+                        "key": "iata"                     },                     "lookup": "origin"                 },                 {-                    "as": "origin_latitude",-                    "calculate": "datum.latitude"-                },-                {-                    "as": "origin_longitude",-                    "calculate": "datum.longitude"-                },-                {+                    "as": "d",                     "from": {                         "data": {                             "url": "https://vega.github.io/vega-lite/data/airports.csv"                         },-                        "key": "iata",-                        "fields": [-                            "latitude",-                            "longitude"-                        ]+                        "key": "iata"                     },                     "lookup": "destination"-                },-                {-                    "as": "dest_latitude",-                    "calculate": "datum.latitude"-                },-                {-                    "as": "dest_longitude",-                    "calculate": "datum.longitude"                 }             ],             "mark": "rule",@@ -105,18 +83,18 @@             },             "encoding": {                 "latitude": {-                    "field": "origin_latitude",+                    "field": "o.latitude",                     "type": "quantitative"                 },                 "latitude2": {-                    "field": "dest_latitude"+                    "field": "d.latitude"                 },                 "longitude": {-                    "field": "origin_longitude",+                    "field": "o.longitude",                     "type": "quantitative"                 },                 "longitude2": {-                    "field": "dest_longitude"+                    "field": "d.longitude"                 }             }         }
tests/specs/gallery/geo/geo5.vl view
@@ -56,6 +56,6 @@             }         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Population per state, engineers per state, and hurricanes per state" }
tests/specs/gallery/geo/geo6.vl view
@@ -6,7 +6,7 @@         }     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/gallery/geo/geo7.vl view
@@ -6,7 +6,7 @@         }     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/gallery/geo/geo8.vl view
@@ -26,7 +26,7 @@         "url": "https://vega.github.io/vega-lite/data/income.json"     },     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/gallery/geo/geo9.vl view
@@ -6,7 +6,7 @@         }     },     "width": 700,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/interaction/interaction1.vl view
@@ -50,7 +50,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "highlight": {             "empty": "none",
tests/specs/gallery/interaction/interaction10.vl view
@@ -7,7 +7,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/seattle-weather.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/interaction/interaction11a.vl view
@@ -1,12 +1,11 @@ {     "mark": "point",     "data": {-        "url": "data/cars.json"+        "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "brush": {-            "init": null,             "type": "interval"         }     },@@ -28,5 +27,5 @@             "type": "quantitative"         }     },-    "description": "Drag out a rectangular brush to hughlight points."+    "description": "Drag out a rectangular brush to highlight points." }
tests/specs/gallery/interaction/interaction11b.vl view
@@ -1,9 +1,9 @@ {     "mark": "point",     "data": {-        "url": "data/cars.json"+        "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "brush": {             "init": {@@ -33,5 +33,5 @@             "type": "quantitative"         }     },-    "description": "Drag out a rectangular brush to hughlight points."+    "description": "Drag out a rectangular brush to highlight points." }
tests/specs/gallery/interaction/interaction11c.vl view
@@ -1,9 +1,9 @@ {     "mark": "point",     "data": {-        "url": "data/cars.json"+        "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "brush": {             "init": {@@ -33,5 +33,5 @@             "type": "quantitative"         }     },-    "description": "Drag out a rectangular brush to hughlight points."+    "description": "Drag out a rectangular brush to highlight points." }
tests/specs/gallery/interaction/interaction11d.vl view
@@ -1,9 +1,9 @@ {     "mark": "point",     "data": {-        "url": "data/cars.json"+        "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "brush": {             "init": {@@ -37,5 +37,5 @@             "type": "quantitative"         }     },-    "description": "Drag out a rectangular brush to hughlight points."+    "description": "Drag out a rectangular brush to highlight points." }
tests/specs/gallery/interaction/interaction2.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Origin",
tests/specs/gallery/interaction/interaction3.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "myBrush": {             "type": "interval"
tests/specs/gallery/interaction/interaction4.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/unemployment-across-industries.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "area",
tests/specs/gallery/interaction/interaction5.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "myPaintbrush": {             "nearest": true,
tests/specs/gallery/interaction/interaction6.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "myGrid": {             "bind": "scales",
tests/specs/gallery/interaction/interaction7.vl view
@@ -8,7 +8,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "circle",
tests/specs/gallery/interaction/interaction8.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/seattle-weather.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar",
tests/specs/gallery/interaction/interaction9.vl view
@@ -9,7 +9,7 @@         }     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "layer": [
tests/specs/gallery/label/label1.vl view
@@ -24,7 +24,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar"
tests/specs/gallery/label/label2.vl view
@@ -11,7 +11,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "rect",
tests/specs/gallery/label/label3.vl view
@@ -32,7 +32,7 @@         }     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/label/label4.vl view
@@ -1,5 +1,5 @@ {-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "data": {
tests/specs/gallery/label/label5.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/seattle-weather.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar",
tests/specs/gallery/label/label6.vl view
@@ -2,7 +2,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar",
tests/specs/gallery/label/label7.vl view
@@ -161,7 +161,7 @@         }     },     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "rect",
tests/specs/gallery/layer/layer1.vl view
@@ -208,7 +208,7 @@         ]     },     "width": 320,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "rule",
tests/specs/gallery/layer/layer2.vl view
@@ -25,7 +25,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/countries.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "line",
tests/specs/gallery/layer/layer3.vl view
@@ -172,7 +172,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "facet": {         "row": {             "field": "title",
tests/specs/gallery/layer/layer4.vl view
@@ -7,7 +7,7 @@             "y": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "bar",
tests/specs/gallery/layer/layer5.vl view
@@ -91,7 +91,7 @@         ]     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/layer/layer6.vl view
@@ -4,7 +4,7 @@         "url": "https://vega.github.io/vega-lite/data/weather.json"     },     "width": 250,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "title": "Weekly Weather Observations and Predictions",     "layer": [         {
tests/specs/gallery/layer/layer7.vl view
@@ -19,7 +19,7 @@         "url": "data/seattle-weather.csv"     },     "width": 400,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/line/line1.vl view
@@ -8,7 +8,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/stocks.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
tests/specs/gallery/line/line10.vl view
@@ -32,7 +32,7 @@         }     },     "width": 800,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/gallery/line/line11.vl view
@@ -102,7 +102,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "team",
tests/specs/gallery/line/line12.vl view
@@ -19,7 +19,7 @@         }     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "line",
tests/specs/gallery/line/line2.vl view
@@ -14,7 +14,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/stocks.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
tests/specs/gallery/line/line3.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/stocks.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "symbol",
tests/specs/gallery/line/line4.vl view
@@ -3,7 +3,10 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/barley.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "width": {+        "step": 50+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "site",@@ -12,7 +15,6 @@         "x": {             "field": "year",             "scale": {-                "rangeStep": 50,                 "padding": 0.5             },             "type": "ordinal"
tests/specs/gallery/line/line5.vl view
@@ -11,7 +11,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/stocks.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
tests/specs/gallery/line/line6.vl view
@@ -11,7 +11,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/stocks.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "date",
tests/specs/gallery/line/line7.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/driving.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "miles",
tests/specs/gallery/line/line8.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/stocks.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "symbol",
tests/specs/gallery/line/line9.vl view
@@ -35,7 +35,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "x",
tests/specs/gallery/multi/multi1.vl view
@@ -56,6 +56,6 @@             }         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Overview and detail." }
tests/specs/gallery/multi/multi2.vl view
@@ -66,5 +66,5 @@         },         "description": "Cross-filter."     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/gallery/multi/multi3.vl view
@@ -55,6 +55,6 @@             }         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Scatterplot matrix" }
tests/specs/gallery/multi/multi4.vl view
@@ -105,6 +105,6 @@             }         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "A dashboard with cross-highlighting" }
tests/specs/gallery/multi/multi5.vl view
@@ -136,7 +136,7 @@             }         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "title": "Seattle Weather, 2012-2015",     "description": "A dashboard with cross-highlighting" }
tests/specs/gallery/multi/multi6.vl view
@@ -158,6 +158,6 @@             "color": "independent"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Drag a rectangular brush to show (first 20) selected points in a table." }
tests/specs/gallery/multi/multi7.vl view
@@ -6,7 +6,7 @@         }     },     "width": 900,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },@@ -33,46 +33,24 @@                     }                 },                 {+                    "as": "o",                     "from": {                         "data": {                             "url": "https://vega.github.io/vega-lite/data/airports.csv"                         },-                        "key": "iata",-                        "fields": [-                            "latitude",-                            "longitude"-                        ]+                        "key": "iata"                     },                     "lookup": "origin"                 },                 {-                    "as": "oLat",-                    "calculate": "datum.latitude"-                },-                {-                    "as": "oLon",-                    "calculate": "datum.longitude"-                },-                {+                    "as": "d",                     "from": {                         "data": {                             "url": "https://vega.github.io/vega-lite/data/airports.csv"                         },-                        "key": "iata",-                        "fields": [-                            "latitude",-                            "longitude"-                        ]+                        "key": "iata"                     },                     "lookup": "destination"-                },-                {-                    "as": "dLat",-                    "calculate": "datum.latitude"-                },-                {-                    "as": "dLon",-                    "calculate": "datum.longitude"                 }             ],             "mark": {@@ -85,18 +63,18 @@             },             "encoding": {                 "latitude": {-                    "field": "oLat",+                    "field": "o.latitude",                     "type": "quantitative"                 },                 "latitude2": {-                    "field": "dLat"+                    "field": "d.latitude"                 },                 "longitude": {-                    "field": "oLon",+                    "field": "o.longitude",                     "type": "quantitative"                 },                 "longitude2": {-                    "field": "dLon"+                    "field": "d.longitude"                 }             }         },@@ -120,6 +98,7 @@                         },                         "key": "iata",                         "fields": [+                            "name",                             "state",                             "latitude",                             "longitude"@@ -161,6 +140,10 @@                 "latitude": {                     "field": "latitude",                     "type": "quantitative"+                },+                "tooltip": {+                    "field": "name",+                    "type": "nominal"                 },                 "longitude": {                     "field": "longitude",
+ tests/specs/gallery/multi/multi8.vl view
@@ -0,0 +1,72 @@+{+    "transform": [+        {+            "as": "time",+            "calculate": "hours(datum.date) + minutes(datum.date) / 60"+        }+    ],+    "data": {+        "url": "https://vega.github.io/vega-lite/data/flights-5k.json",+        "format": {+            "parse": {+                "date": "date"+            }+        }+    },+    "vconcat": [+        {+            "height": 100,+            "mark": "bar",+            "width": 963,+            "selection": {+                "brush": {+                    "init": {+                        "x": [+                            6,+                            12+                        ]+                    },+                    "encodings": [+                        "x"+                    ],+                    "type": "interval"+                }+            },+            "encoding": {+                "x": {+                    "field": "time",+                    "bin": {+                        "maxbins": 30+                    },+                    "type": "quantitative"+                },+                "y": {+                    "aggregate": "count",+                    "type": "quantitative"+                }+            }+        },+        {+            "height": 100,+            "mark": "bar",+            "width": 963,+            "encoding": {+                "x": {+                    "field": "time",+                    "bin": {+                        "maxbins": 30,+                        "extent": {+                            "selection": "brush"+                        }+                    },+                    "type": "quantitative"+                },+                "y": {+                    "aggregate": "count",+                    "type": "quantitative"+                }+            }+        }+    ],+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json"+}
tests/specs/gallery/repeat/repeat1.vl view
@@ -63,6 +63,6 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Monthly weather information for individual years and overall average for Seatle and New York" }
tests/specs/gallery/repeat/repeat2.vl view
@@ -43,6 +43,6 @@             }         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Two vertically concatenated charts that show a histogram of precipitation in Seattle and the relationship between min and max temperature" }
tests/specs/gallery/repeat/repeat3.vl view
@@ -29,6 +29,6 @@             }         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Horizontally repeated charts that show the histograms of different parameters of cars in different countries" }
tests/specs/gallery/repeat/repeat4.vl view
@@ -55,6 +55,6 @@             }         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Scatterplot matrix" }
tests/specs/gallery/repeat/repeat5.vl view
@@ -89,7 +89,7 @@             "bounds": "flush"         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "description": "Marginal histograms show the counts along the x and y dimension",     "spacing": 15,     "bounds": "flush"
tests/specs/gallery/scatter/scatter1.vl view
@@ -8,7 +8,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Horsepower",
tests/specs/gallery/scatter/scatter10.vl view
@@ -15,7 +15,7 @@         "url": "https://vega.github.io/vega-lite/data/disasters.csv"     },     "width": 600,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Entity",
tests/specs/gallery/scatter/scatter11.vl view
@@ -9,7 +9,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Origin",
tests/specs/gallery/scatter/scatter2.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/seattle-weather.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "precipitation",
tests/specs/gallery/scatter/scatter3.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Horsepower",
tests/specs/gallery/scatter/scatter4.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Origin",
tests/specs/gallery/scatter/scatter5.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "size": {             "aggregate": "count",
tests/specs/gallery/scatter/scatter6.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "size": {             "field": "Acceleration",
tests/specs/gallery/scatter/scatter7.vl view
@@ -1,12 +1,14 @@ {     "config": {-        "invalidValues": null+        "mark": {+            "invalid": null+        }     },     "mark": "point",     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "value": "rgb(76,120,168)",
tests/specs/gallery/scatter/scatter8.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "x": {             "field": "Horsepower",
tests/specs/gallery/scatter/scatter9.vl view
@@ -5,7 +5,7 @@         "url": "https://vega.github.io/vega-lite/data/gapminder-health-income.csv"     },     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "view": {             "bind": "scales",
+ tests/specs/gallery/scatter/smoothing1.vl view
@@ -0,0 +1,59 @@+{+    "height": 300,+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "opacity": 0.3,+                "type": "point",+                "filled": true+            }+        },+        {+            "transform": [+                {+                    "bandwidth": 0.1,+                    "loess": "IMDB_Rating",+                    "on": "Rotten_Tomatoes_Rating"+                }+            ],+            "mark": {+                "color": "firebrick",+                "type": "line"+            }+        },+        {+            "transform": [+                {+                    "extent": [+                        10,+                        90+                    ],+                    "method": "poly",+                    "regression": "IMDB_Rating",+                    "order": 3,+                    "on": "Rotten_Tomatoes_Rating"+                }+            ],+            "mark": {+                "color": "orange",+                "type": "line"+            }+        }+    ],+    "encoding": {+        "x": {+            "field": "Rotten_Tomatoes_Rating",+            "type": "quantitative"+        },+        "y": {+            "field": "IMDB_Rating",+            "type": "quantitative"+        }+    },+    "description": "How can we 'smooth' data?"+}
+ tests/specs/gallery/scatter/smoothing2.vl view
@@ -0,0 +1,80 @@+{+    "height": 300,+    "data": {+        "url": "https://vega.github.io/vega-lite/data/movies.json"+    },+    "width": 300,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "opacity": 0.3,+                "type": "point",+                "filled": true+            },+            "encoding": {+                "x": {+                    "field": "Rotten_Tomatoes_Rating",+                    "type": "quantitative"+                },+                "y": {+                    "field": "IMDB_Rating",+                    "type": "quantitative"+                }+            }+        },+        {+            "transform": [+                {+                    "as": [+                        "Rotten_Tomatoes_Rating",+                        "ly"+                    ],+                    "loess": "IMDB_Rating",+                    "on": "Rotten_Tomatoes_Rating"+                }+            ],+            "mark": {+                "color": "firebrick",+                "type": "line"+            },+            "encoding": {+                "x": {+                    "field": "Rotten_Tomatoes_Rating",+                    "type": "quantitative"+                },+                "y": {+                    "field": "ly",+                    "type": "quantitative"+                }+            }+        },+        {+            "transform": [+                {+                    "as": [+                        "Rotten_Tomatoes_Rating",+                        "ry"+                    ],+                    "regression": "IMDB_Rating",+                    "on": "Rotten_Tomatoes_Rating"+                }+            ],+            "mark": {+                "color": "orange",+                "type": "line"+            },+            "encoding": {+                "x": {+                    "field": "Rotten_Tomatoes_Rating",+                    "type": "quantitative"+                },+                "y": {+                    "field": "ry",+                    "type": "quantitative"+                }+            }+        }+    ],+    "description": "How can we 'smooth' and rename data?"+}
tests/specs/gallery/table/table1.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "Horsepower",
tests/specs/gallery/table/table2.vl view
@@ -1,10 +1,8 @@ {     "config": {-        "scale": {-            "rangeStep": 13-        },         "view": {-            "strokeWidth": 0+            "strokeWidth": 0,+            "step": 13         },         "axis": {             "domain": false@@ -14,7 +12,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/seattle-temps.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "temp",
tests/specs/gallery/table/table3.vl view
@@ -31,7 +31,7 @@         "url": "https://vega.github.io/vega-lite/data/movies.json"     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "aggregate": "count",
tests/specs/gallery/table/table4.vl view
@@ -3,7 +3,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/github.csv"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "size": {             "field": "count",
tests/specs/gallery/table/table5.vl view
@@ -11,7 +11,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/cars.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": "rect",
tests/specs/geo/choropleth1.vl view
@@ -17,7 +17,7 @@         }     },     "width": 900,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "id",
tests/specs/geo/choropleth2.vl view
@@ -6,7 +6,7 @@         }     },     "width": 1200,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/geo/defaultSize1.vl view
@@ -7,7 +7,7 @@             "type": "topojson"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/geo/defaultSize2.vl view
@@ -1,8 +1,8 @@ {     "config": {         "view": {-            "height": 300,-            "width": 500+            "continuousHeight": 300,+            "continuousWidth": 500         }     },     "mark": "geoshape",@@ -13,7 +13,7 @@             "type": "topojson"         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/geo/dotMap1.vl view
@@ -11,7 +11,7 @@         "url": "https://vega.github.io/vega-lite/data/zipcodes.csv"     },     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/geo/graticule1.vl view
@@ -1,7 +1,7 @@ {     "height": 300,     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic",         "rotate": [
tests/specs/geo/graticule2.vl view
@@ -1,7 +1,7 @@ {     "height": 300,     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic",         "rotate": [
tests/specs/geo/graticule3.vl view
@@ -1,7 +1,7 @@ {     "height": 300,     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic",         "rotate": [
tests/specs/geo/graticule4.vl view
@@ -1,7 +1,7 @@ {     "height": 300,     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic",         "rotate": [
tests/specs/geo/linear1.vl view
@@ -12,7 +12,7 @@         }     },     "width": 700,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "id",
tests/specs/geo/linear2.vl view
@@ -18,7 +18,7 @@         }     },     "width": 700,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "field": "id",
tests/specs/geo/linear3.vl view
@@ -6,7 +6,7 @@         }     },     "width": 700,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/geo/map1d.vl view
@@ -1,7 +1,7 @@ {     "height": 400,     "width": 500,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/geo/mapComp1.vl view
@@ -55,5 +55,5 @@             }         }     ],-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/geo/mapComp2.vl view
@@ -120,5 +120,5 @@             "stroke": null         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/geo/mapComp3.vl view
@@ -168,5 +168,5 @@             "stroke": null         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/geo/mapComp4.vl view
@@ -162,5 +162,5 @@             "stroke": null         }     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json"+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json" }
tests/specs/geo/scale1.vl view
@@ -1,7 +1,7 @@ {     "height": 300,     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "scale": 470,         "type": "orthographic"
tests/specs/geo/scribbleMap1.vl view
@@ -28,7 +28,7 @@         "url": "https://vega.github.io/vega-lite/data/zipcodes.csv"     },     "width": 1000,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/geo/scribbleMap2.vl view
@@ -32,7 +32,7 @@         "url": "https://vega.github.io/vega-lite/data/zipcodes.csv"     },     "width": 1000,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "albersUsa"     },
tests/specs/geo/sphere1.vl view
@@ -12,7 +12,7 @@         }     },     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic"     }
tests/specs/geo/sphere2.vl view
@@ -1,7 +1,7 @@ {     "height": 300,     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic"     },
tests/specs/geo/translate1.vl view
@@ -1,7 +1,7 @@ {     "height": 300,     "width": 300,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "projection": {         "type": "orthographic",         "translate": [
tests/specs/hyperlink/hyperlink1.vl view
@@ -11,7 +11,7 @@             }         ]     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "layer": [         {             "mark": {
tests/specs/hyperlink/hyperlink2.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "href": {             "value": "http://www.imdb.com"
tests/specs/hyperlink/hyperlink3.vl view
@@ -6,7 +6,7 @@     "data": {         "url": "https://vega.github.io/vega-lite/data/movies.json"     },-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "encoding": {         "color": {             "value": "red",
+ tests/specs/image/image1.vl view
@@ -0,0 +1,37 @@+{+    "mark": {+        "height": 25,+        "width": 25,+        "type": "image"+    },+    "data": {+        "values": [+            {+                "x": 0.5,+                "y": 0.5+            },+            {+                "x": 1.5,+                "y": 1.5+            },+            {+                "x": 2.5,+                "y": 2.5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "url": {+            "value": "https://vega.github.io/vega-lite/data/ffox.png"+        },+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/image/image10.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "height": 61,+                "width": 100,+                "type": "image",+                "baseline": "bottom"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/image/image2.vl view
@@ -0,0 +1,41 @@+{+    "mark": {+        "height": 25,+        "width": 25,+        "type": "image"+    },+    "data": {+        "values": [+            {+                "img": "https://vega.github.io/vega-lite/data/ffox.png",+                "x": 0.5,+                "y": 0.5+            },+            {+                "img": "https://vega.github.io/vega-lite/data/gimp.png",+                "x": 1.5,+                "y": 1.5+            },+            {+                "img": "https://vega.github.io/vega-lite/data/7zip.png",+                "x": 2.5,+                "y": 2.5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "encoding": {+        "url": {+            "field": "img",+            "type": "nominal"+        },+        "x": {+            "field": "x",+            "type": "quantitative"+        },+        "y": {+            "field": "y",+            "type": "quantitative"+        }+    }+}
+ tests/specs/image/image3.vl view
@@ -0,0 +1,75 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "aspect": true,+                "width": 100,+                "type": "image"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/image/image4.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "height": 100,+                "aspect": false,+                "width": 100,+                "type": "image"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/image/image5.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "height": 61,+                "width": 100,+                "align": "left",+                "type": "image"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/image/image6.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "height": 61,+                "width": 100,+                "align": "center",+                "type": "image"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/image/image7.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "height": 61,+                "width": 100,+                "align": "right",+                "type": "image"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/image/image8.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "height": 61,+                "width": 100,+                "type": "image",+                "baseline": "top"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/image/image9.vl view
@@ -0,0 +1,76 @@+{+    "data": {+        "values": [+            {+                "x": 5,+                "y": 5+            }+        ]+    },+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "layer": [+        {+            "mark": {+                "height": 61,+                "width": 100,+                "type": "image",+                "baseline": "middle"+            },+            "encoding": {+                "url": {+                    "value": "https://gicentre.github.io/data/images/LillyTarn.jpg"+                },+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        },+        {+            "mark": {+                "color": "red",+                "size": 100,+                "opacity": 0.5,+                "type": "circle"+            },+            "encoding": {+                "x": {+                    "field": "x",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                },+                "y": {+                    "field": "y",+                    "scale": {+                        "domain": [+                            0,+                            10+                        ]+                    },+                    "type": "quantitative"+                }+            }+        }+    ]+}
+ tests/specs/interaction/bindlegend.vl view
@@ -0,0 +1,62 @@+{+    "mark": "circle",+    "data": {+        "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"+    },+    "width": 540,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "mySelection": {+            "bind": "legend",+            "type": "single",+            "fields": [+                "crimeType"+            ]+        }+    },+    "encoding": {+        "color": {+            "value": "black",+            "condition": {+                "field": "crimeType",+                "scale": {+                    "domain": [+                        "Anti-social behaviour",+                        "Burglary",+                        "Criminal damage and arson",+                        "Drugs",+                        "Robbery",+                        "Vehicle crime"+                    ],+                    "range": [+                        "rgb(59,118,175)",+                        "rgb(81,157,62)",+                        "rgb(141,106,184)",+                        "rgb(239,133,55)",+                        "rgb(132,88,78)",+                        "rgb(213,126,190)"+                    ]+                },+                "selection": "mySelection",+                "type": "nominal"+            }+        },+        "opacity": {+            "value": 0.1,+            "condition": {+                "value": 1,+                "selection": "mySelection"+            }+        },+        "x": {+            "field": "month",+            "title": null,+            "type": "temporal"+        },+        "y": {+            "field": "reportedCrimes",+            "title": "Reported crimes",+            "type": "quantitative"+        }+    }+}
+ tests/specs/interaction/bindlegend2.vl view
@@ -0,0 +1,64 @@+{+    "mark": "circle",+    "data": {+        "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"+    },+    "width": 540,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "mySelection": {+            "bind": {+                "legend": "dblclick"+            },+            "encodings": [+                "color"+            ],+            "type": "single"+        }+    },+    "encoding": {+        "color": {+            "value": "black",+            "condition": {+                "field": "crimeType",+                "scale": {+                    "domain": [+                        "Anti-social behaviour",+                        "Burglary",+                        "Criminal damage and arson",+                        "Drugs",+                        "Robbery",+                        "Vehicle crime"+                    ],+                    "range": [+                        "rgb(59,118,175)",+                        "rgb(81,157,62)",+                        "rgb(141,106,184)",+                        "rgb(239,133,55)",+                        "rgb(132,88,78)",+                        "rgb(213,126,190)"+                    ]+                },+                "selection": "mySelection",+                "type": "nominal"+            }+        },+        "opacity": {+            "value": 0.1,+            "condition": {+                "value": 1,+                "selection": "mySelection"+            }+        },+        "x": {+            "field": "month",+            "title": null,+            "type": "temporal"+        },+        "y": {+            "field": "reportedCrimes",+            "title": "Reported crimes",+            "type": "quantitative"+        }+    }+}
+ tests/specs/interaction/bindlegendboth.vl view
@@ -0,0 +1,65 @@+{+    "mark": "circle",+    "data": {+        "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"+    },+    "width": 540,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "mySelection": {+            "bind": {+                "legend": "dblclick"+            },+            "type": "multi",+            "on": "click",+            "fields": [+                "crimeType"+            ]+        }+    },+    "encoding": {+        "color": {+            "value": "black",+            "condition": {+                "field": "crimeType",+                "scale": {+                    "domain": [+                        "Anti-social behaviour",+                        "Burglary",+                        "Criminal damage and arson",+                        "Drugs",+                        "Robbery",+                        "Vehicle crime"+                    ],+                    "range": [+                        "rgb(59,118,175)",+                        "rgb(81,157,62)",+                        "rgb(141,106,184)",+                        "rgb(239,133,55)",+                        "rgb(132,88,78)",+                        "rgb(213,126,190)"+                    ]+                },+                "selection": "mySelection",+                "type": "nominal"+            }+        },+        "opacity": {+            "value": 0.1,+            "condition": {+                "value": 1,+                "selection": "mySelection"+            }+        },+        "x": {+            "field": "month",+            "title": null,+            "type": "temporal"+        },+        "y": {+            "field": "reportedCrimes",+            "title": "Reported crimes",+            "type": "quantitative"+        }+    }+}
+ tests/specs/interaction/initinterval.vl view
@@ -0,0 +1,58 @@+{+    "mark": "circle",+    "data": {+        "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"+    },+    "width": 540,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "mySelection": {+            "type": "interval"+        }+    },+    "encoding": {+        "color": {+            "value": "black",+            "condition": {+                "field": "crimeType",+                "scale": {+                    "domain": [+                        "Anti-social behaviour",+                        "Burglary",+                        "Criminal damage and arson",+                        "Drugs",+                        "Robbery",+                        "Vehicle crime"+                    ],+                    "range": [+                        "rgb(59,118,175)",+                        "rgb(81,157,62)",+                        "rgb(141,106,184)",+                        "rgb(239,133,55)",+                        "rgb(132,88,78)",+                        "rgb(213,126,190)"+                    ]+                },+                "selection": "mySelection",+                "type": "nominal"+            }+        },+        "opacity": {+            "value": 0.1,+            "condition": {+                "value": 1,+                "selection": "mySelection"+            }+        },+        "x": {+            "field": "month",+            "title": null,+            "type": "temporal"+        },+        "y": {+            "field": "reportedCrimes",+            "title": "Reported crimes",+            "type": "quantitative"+        }+    }+}
+ tests/specs/interaction/initintervalx.vl view
@@ -0,0 +1,71 @@+{+    "mark": "circle",+    "data": {+        "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"+    },+    "width": 540,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "mySelection": {+            "init": {+                "x": [+                    {+                        "year": 2013+                    },+                    {+                        "year": 2015+                    }+                ]+            },+            "encodings": [+                "x"+            ],+            "type": "interval"+        }+    },+    "encoding": {+        "color": {+            "value": "black",+            "condition": {+                "field": "crimeType",+                "scale": {+                    "domain": [+                        "Anti-social behaviour",+                        "Burglary",+                        "Criminal damage and arson",+                        "Drugs",+                        "Robbery",+                        "Vehicle crime"+                    ],+                    "range": [+                        "rgb(59,118,175)",+                        "rgb(81,157,62)",+                        "rgb(141,106,184)",+                        "rgb(239,133,55)",+                        "rgb(132,88,78)",+                        "rgb(213,126,190)"+                    ]+                },+                "selection": "mySelection",+                "type": "nominal"+            }+        },+        "opacity": {+            "value": 0.1,+            "condition": {+                "value": 1,+                "selection": "mySelection"+            }+        },+        "x": {+            "field": "month",+            "title": null,+            "type": "temporal"+        },+        "y": {+            "field": "reportedCrimes",+            "title": "Reported crimes",+            "type": "quantitative"+        }+    }+}
+ tests/specs/interaction/initintervalxy.vl view
@@ -0,0 +1,72 @@+{+    "mark": "circle",+    "data": {+        "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"+    },+    "width": 540,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "mySelection": {+            "init": {+                "x": [+                    {+                        "year": 2013+                    },+                    {+                        "year": 2015+                    }+                ],+                "y": [+                    4000,+                    8000+                ]+            },+            "type": "interval"+        }+    },+    "encoding": {+        "color": {+            "value": "black",+            "condition": {+                "field": "crimeType",+                "scale": {+                    "domain": [+                        "Anti-social behaviour",+                        "Burglary",+                        "Criminal damage and arson",+                        "Drugs",+                        "Robbery",+                        "Vehicle crime"+                    ],+                    "range": [+                        "rgb(59,118,175)",+                        "rgb(81,157,62)",+                        "rgb(141,106,184)",+                        "rgb(239,133,55)",+                        "rgb(132,88,78)",+                        "rgb(213,126,190)"+                    ]+                },+                "selection": "mySelection",+                "type": "nominal"+            }+        },+        "opacity": {+            "value": 0.1,+            "condition": {+                "value": 1,+                "selection": "mySelection"+            }+        },+        "x": {+            "field": "month",+            "title": null,+            "type": "temporal"+        },+        "y": {+            "field": "reportedCrimes",+            "title": "Reported crimes",+            "type": "quantitative"+        }+    }+}
+ tests/specs/interaction/initintervaly.vl view
@@ -0,0 +1,64 @@+{+    "mark": "circle",+    "data": {+        "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"+    },+    "width": 540,+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",+    "selection": {+        "mySelection": {+            "init": {+                "y": [+                    4000,+                    8000+                ]+            },+            "type": "interval"+        }+    },+    "encoding": {+        "color": {+            "value": "black",+            "condition": {+                "field": "crimeType",+                "scale": {+                    "domain": [+                        "Anti-social behaviour",+                        "Burglary",+                        "Criminal damage and arson",+                        "Drugs",+                        "Robbery",+                        "Vehicle crime"+                    ],+                    "range": [+                        "rgb(59,118,175)",+                        "rgb(81,157,62)",+                        "rgb(141,106,184)",+                        "rgb(239,133,55)",+                        "rgb(132,88,78)",+                        "rgb(213,126,190)"+                    ]+                },+                "selection": "mySelection",+                "type": "nominal"+            }+        },+        "opacity": {+            "value": 0.1,+            "condition": {+                "value": 1,+                "selection": "mySelection"+            }+        },+        "x": {+            "field": "month",+            "title": null,+            "type": "temporal"+        },+        "y": {+            "field": "reportedCrimes",+            "title": "Reported crimes",+            "type": "quantitative"+        }+    }+}
tests/specs/interaction/interaction1.vl view
@@ -4,7 +4,7 @@         "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"     },     "width": 540,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "mySelection": {             "type": "single"
tests/specs/interaction/interaction2.vl view
@@ -4,7 +4,7 @@         "url": "https://gicentre.github.io/data/westMidlands/westMidsCrimesAggregated.tsv"     },     "width": 540,-    "$schema": "https://vega.github.io/schema/vega-lite/v3.json",+    "$schema": "https://vega.github.io/schema/vega-lite/v4.json",     "selection": {         "mySelection": {             "type": "multi"
tests/specs/interaction/interaction3.vl view

file too large to diff

tests/specs/interaction/interaction4.vl view

file too large to diff

tests/specs/interaction/interaction5.vl view

file too large to diff

tests/specs/interaction/interaction6.vl view

file too large to diff

tests/specs/interaction/interaction7.vl view

file too large to diff

tests/specs/interaction/interaction8.vl view

file too large to diff

+ tests/specs/interaction/lookupSelection1.vl view

file too large to diff

+ tests/specs/legend/corners1.vl view

file too large to diff

+ tests/specs/legend/corners2.vl view

file too large to diff

tests/specs/legend/legend1.vl view

file too large to diff

tests/specs/legend/legend10.vl view

file too large to diff

tests/specs/legend/legend11.vl view

file too large to diff

+ tests/specs/legend/legend11d.vl view

file too large to diff

tests/specs/legend/legend2.vl view

file too large to diff

tests/specs/legend/legend3.vl view

file too large to diff

tests/specs/legend/legend4.vl view

file too large to diff

tests/specs/legend/legend5.vl view

file too large to diff

tests/specs/legend/legend6.vl view

file too large to diff

tests/specs/legend/legend7.vl view

file too large to diff

tests/specs/legend/legend8.vl view

file too large to diff

tests/specs/legend/legend9.vl view

file too large to diff

tests/specs/null/axis1.vl view

file too large to diff

tests/specs/null/filter1.vl view

file too large to diff

tests/specs/null/filter2.vl view

file too large to diff

tests/specs/null/scale0.vl view

file too large to diff

tests/specs/null/scale1.vl view

file too large to diff

tests/specs/null/scale2.vl view

file too large to diff

tests/specs/null/scale3.vl view

file too large to diff

tests/specs/null/scale4.vl view

file too large to diff

tests/specs/null/scale5.vl view

file too large to diff

tests/specs/position/position1.vl view

file too large to diff

tests/specs/position/position10.vl view

file too large to diff

tests/specs/position/position11.vl view

file too large to diff

tests/specs/position/position12.vl view

file too large to diff

tests/specs/position/position2.vl view

file too large to diff

tests/specs/position/position3.vl view

file too large to diff

tests/specs/position/position4.vl view

file too large to diff

tests/specs/position/position5.vl view

file too large to diff

tests/specs/position/position6.vl view

file too large to diff

tests/specs/position/position7.vl view

file too large to diff

tests/specs/position/position8.vl view

file too large to diff

tests/specs/position/position9.vl view

file too large to diff

tests/specs/projection/Albers.vl view

file too large to diff

tests/specs/projection/AzimuthalEqualArea.vl view

file too large to diff

tests/specs/projection/AzimuthalEquidistant.vl view

file too large to diff

tests/specs/projection/ConicConformal.vl view

file too large to diff

tests/specs/projection/ConicEqualArea.vl view

file too large to diff

tests/specs/projection/ConicEquidistant.vl view

file too large to diff

+ tests/specs/projection/EqualEarth.vl view

file too large to diff

tests/specs/projection/Equirectangular.vl view

file too large to diff

tests/specs/projection/Gnomonic.vl view

file too large to diff

tests/specs/projection/Identity.vl view

file too large to diff

tests/specs/projection/Mercator.vl view

file too large to diff

+ tests/specs/projection/NaturalEarth1.vl view

file too large to diff

tests/specs/projection/Orthographic.vl view

file too large to diff

tests/specs/projection/Stereographic.vl view

file too large to diff

tests/specs/projection/TransverseMercator.vl view

file too large to diff

tests/specs/projection/airy.vl view

file too large to diff

tests/specs/projection/aitoff.vl view

file too large to diff

tests/specs/projection/armadillo.vl view

file too large to diff

tests/specs/projection/august.vl view

file too large to diff

tests/specs/projection/baker.vl view

file too large to diff

tests/specs/projection/berghaus.vl view

file too large to diff

tests/specs/projection/bertin1953.vl view

file too large to diff

tests/specs/projection/boggs.vl view

file too large to diff

tests/specs/projection/bonne.vl view

file too large to diff

tests/specs/projection/bottomley.vl view

file too large to diff

tests/specs/projection/collignon.vl view

file too large to diff

tests/specs/projection/configExample.vl view

file too large to diff

tests/specs/projection/craig.vl view

file too large to diff

tests/specs/projection/craster.vl view

file too large to diff

tests/specs/projection/cylindricalequalarea.vl view

file too large to diff

tests/specs/projection/cylindricalstereographic.vl view

file too large to diff

tests/specs/projection/eckert1.vl view

file too large to diff

tests/specs/projection/eckert2.vl view

file too large to diff

tests/specs/projection/eckert3.vl view

file too large to diff

tests/specs/projection/eckert4.vl view

file too large to diff

tests/specs/projection/eckert5.vl view

file too large to diff

tests/specs/projection/eckert6.vl view

file too large to diff

tests/specs/projection/eisenlohr.vl view

file too large to diff

tests/specs/projection/fahey.vl view

file too large to diff

tests/specs/projection/foucaut.vl view

file too large to diff

tests/specs/projection/gingery.vl view

file too large to diff

tests/specs/projection/identityExample.vl view

file too large to diff

tests/specs/projection/reflectXExample.vl view

file too large to diff

tests/specs/projection/reflectXYExample.vl view

file too large to diff

tests/specs/projection/reflectYExample.vl view

file too large to diff

tests/specs/projection/winkel3.vl view

file too large to diff

tests/specs/scale/scale1.vl view

file too large to diff

tests/specs/scale/scale2.vl view

file too large to diff

tests/specs/scale/scale3.vl view

file too large to diff

tests/specs/scale/scale4.vl view

file too large to diff

tests/specs/scale/scale5.vl view

file too large to diff

tests/specs/scale/scale6.vl view

file too large to diff

tests/specs/scale/scale7.vl view

file too large to diff

tests/specs/scale/scale8.vl view

file too large to diff

tests/specs/scale/scale9.vl view

file too large to diff

tests/specs/shape/custom1.vl view

file too large to diff

tests/specs/shape/custom2.vl view

file too large to diff

tests/specs/shape/custom3.vl view

file too large to diff

tests/specs/shape/custom4.vl view

file too large to diff

tests/specs/shape/defNominal.vl view

file too large to diff

tests/specs/shape/defOrdinal.vl view

file too large to diff

tests/specs/shape/isotype1.vl view

file too large to diff

tests/specs/shape/multi1.vl view

file too large to diff

tests/specs/shape/multi2.vl view

file too large to diff

tests/specs/shape/multi3.vl view

file too large to diff

tests/specs/shape/multi4.vl view

file too large to diff

tests/specs/shape/multi5.vl view

file too large to diff

tests/specs/shape/multi6.vl view

file too large to diff

tests/specs/shape/point1.vl view

file too large to diff

tests/specs/shape/point2.vl view

file too large to diff

tests/specs/shape/point3.vl view

file too large to diff

tests/specs/shape/point4.vl view

file too large to diff

tests/specs/shape/point5.vl view

file too large to diff

tests/specs/shape/point6.vl view

file too large to diff

tests/specs/shape/point7.vl view

file too large to diff

+ tests/specs/shape/rounded1.vl view

file too large to diff

+ tests/specs/shape/rounded2.vl view

file too large to diff

+ tests/specs/shape/rounded3.vl view

file too large to diff

+ tests/specs/shape/rounded4.vl view

file too large to diff

+ tests/specs/shape/rounded5.vl view

file too large to diff

+ tests/specs/shape/rounded6.vl view

file too large to diff

tests/specs/shape/size1.vl view

file too large to diff

tests/specs/shape/size2.vl view

file too large to diff

tests/specs/shape/size3.vl view

file too large to diff

+ tests/specs/shape/symbols1.vl view

file too large to diff

+ tests/specs/shape/symbols2.vl view

file too large to diff

tests/specs/sort/ascending.vl view

file too large to diff

tests/specs/sort/custom.vl view

file too large to diff

tests/specs/sort/descending.vl view

file too large to diff

tests/specs/sort/stack1.vl view

file too large to diff

tests/specs/sort/weighted.vl view

file too large to diff

tests/specs/textformat/textFormat1.vl view

file too large to diff

tests/specs/textformat/textFormat2.vl view

file too large to diff

+ tests/specs/textformat/tstring.vl view

file too large to diff

tests/specs/time/localTime.vl view

file too large to diff

+ tests/specs/time/timeBand.vl view

file too large to diff

tests/specs/time/timeDate.vl view

file too large to diff

tests/specs/time/timeDay.vl view

file too large to diff

tests/specs/time/timeHours.vl view

file too large to diff

tests/specs/time/timeHoursMinutes.vl view

file too large to diff

tests/specs/time/timeHoursMinutesSeconds.vl view

file too large to diff

tests/specs/time/timeMinutes.vl view

file too large to diff

tests/specs/time/timeMinutesSeconds.vl view

file too large to diff

tests/specs/time/timeMonth.vl view

file too large to diff

tests/specs/time/timeMonthDate.vl view

file too large to diff

tests/specs/time/timeQuarter.vl view

file too large to diff

tests/specs/time/timeQuarterMonth.vl view

file too large to diff

tests/specs/time/timeYear.vl view

file too large to diff

tests/specs/time/timeYearMonthDateHours.vl view

file too large to diff

tests/specs/time/timeYearMonthDateHoursMinutes.vl view

file too large to diff

tests/specs/time/timeYearMonthDateHoursMinutesSeconds.vl view

file too large to diff

tests/specs/time/utcTime.vl view

file too large to diff

+ tests/specs/tooltip/notips.vl view

file too large to diff

tests/specs/tooltip/tooltip1.vl view

file too large to diff

tests/specs/tooltip/tooltip2.vl view

file too large to diff

tests/specs/trail/trail1.vl view

file too large to diff

tests/specs/trail/trail2.vl view

file too large to diff

tests/specs/viewcomposition/columns1.vl view

file too large to diff

tests/specs/viewcomposition/columns2.vl view

file too large to diff

tests/specs/viewcomposition/columns3.vl view

file too large to diff

tests/specs/viewcomposition/columns4.vl view

file too large to diff

tests/specs/viewcomposition/grid1.vl view

file too large to diff

tests/specs/viewcomposition/grid2.vl view

file too large to diff

tests/specs/viewcomposition/grid3.vl view

file too large to diff

tests/specs/viewcomposition/grid4.vl view

file too large to diff

tests/specs/viewcomposition/grid5.vl view

file too large to diff

tests/specs/windowtransform/joinAggregate1.vl view

file too large to diff

tests/specs/windowtransform/joinAggregate2.vl view

file too large to diff

tests/specs/windowtransform/joinAggregate3.vl view

file too large to diff

tests/specs/windowtransform/window1.vl view

file too large to diff

tests/specs/windowtransform/window2.vl view

file too large to diff

tests/specs/windowtransform/window3.vl view

file too large to diff

tests/specs/windowtransform/window4.vl view

file too large to diff

tests/specs/windowtransform/window5.vl view

file too large to diff

tests/specs/windowtransform/window6.vl view

file too large to diff

tests/specs/windowtransform/window7.vl view

file too large to diff

tools/PlayTutorial.hs view

file too large to diff