Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes in next release #15

Closed
jwoLondon opened this issue Aug 14, 2019 · 8 comments
Closed

Changes in next release #15

jwoLondon opened this issue Aug 14, 2019 · 8 comments

Comments

@jwoLondon
Copy link
Member

I've created a working document listing changes for the next release which will support the new Vega-Lite 4 schema. I will be using this as an opportunity to implement any necessary breaking changes to the API, but would like to keep these to a minimum.

Vega-Lite 4 is still under development, so this is a work in progress and may change to reflect further changes to the Vega-Lite schema.

This should be useful for @DougBurke in keeping the Haskell port hvega up to date.

Feel free to use this issue to comment on or propose any changes prior to the next release.

@DougBurke
Copy link
Contributor

Nooooooo. More changes to follow....

:-)

Ta

@DougBurke
Copy link
Contributor

When I created hvega I came up with the following type aliases (well, some have been added later, and you already have LabelledSpec) to help me understand the structure a bit better. I don't know if they would be of interest to you (where my VLSpec is a type alias for the Haskell JSON type) and Haskell's type is synonymous to Elm's type alias, I believe:

{-|

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]

{-|

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

@DougBurke
Copy link
Contributor

I have also created my own type for the zindex value, since it seems to really be 0 or 1 (although the docs are unclear whether other values have any possible meaning, and I could see it changing in the future):

{-|

At what "depth" (z index) is the item to be drawn (a relative depth
for items in the visualization).

@since 0.4.0.0
-}

data ZIndex =
  ZBack
  -- ^ The item is drawn behind (this corresponds to the Vega Lite
  --   @0@ value).
  | ZFront
  -- ^ The item is drawn in front (this corresponds to the Vega Lite
  --   @1@ value).
  | ZValue Natural
  -- ^ This is provided in case there is any need to use a z index value
  --   other than @0@ or @1@.

@jwoLondon
Copy link
Member Author

Thanks for these suggestions. There is some debate in the Elm community as to the benefits of type aliasing (see, this thread for example).

I am not sure I have a consistent view on the matter. My instinct would be to include more type aliases like the examples you provide, but it would appear that some people find the additional level of abstraction unhelpful.

I had a look again at why I chose to create the alias Data, DataColumn and DataRow given they are just ( VLProperty, Spec ), List LabelledSpec and Spec which are used by many other functions. In these cases I found that without the alias, it really wasn't clear which functions were creating data fields and which were modifying the properties of a specification. While underneath everything is a JSON spec, it seemed helpful to differentiate the semantic differences in these cases.

For other cases (and I'd argue opacity and angle fall into this category), the semantic meaning of a parameter seems clearer and more straightforward so I feel there is less benefit in the alias.

Color is an interesting case though, but for slightly different reasons. I can imagine that we might in the future have stronger typing for a color specification rather than relying on an arbitrary string. Perhaps there is an argument to abstract this in order to prepare the way such changes. On the same grounds, we might alias Expression for Vega expressions that are used by a number of functions (e.g. fiExpr and axLabelExpr and shortly hdLabelExpr).

@jwoLondon
Copy link
Member Author

jwoLondon commented Aug 24, 2019

On the z-index. There are a few cases where more than 1 and 0 may be needed. In the example below, three values of axis z-index are used to position x gridlines above y gridlines above circles. I don't think this could be achieved with z-indices of 1 and 0 only.

zOrderTest : Spec
zOrderTest =
    let
        data =
            dataFromColumns []
                << dataColumn "x" (nums [ 20, 10 ])
                << dataColumn "y" (nums [ 10, 20 ])
                << dataColumn "cat" (strs [ "a", "b" ])

        enc =
            encoding
                << position X [ pName "x", pQuant, pAxis [ axZIndex 2 ] ]
                << position Y [ pName "y", pQuant, pAxis [ axZIndex 1 ] ]
                << color [ mName "cat", mMType Nominal, mLegend [] ]

        cfg =
            configure
                << configuration (coAxis [ axcoGridWidth 8 ])
                << configuration (coAxisX [ axcoGridColor "red" ])
                << configuration (coAxisY [ axcoGridColor "blue" ])
    in
    toVegaLite [ cfg [], data [], enc [], circle [ maSize 5000, maOpacity 1 ] ]

zIndex

While your ZFront and ZBack help to clarify in most situations and you have the flexibility with ZValue, hiding the fact that back and front correspond to 0 and 1 may make it more confusing on the rare occasions a user wishes to add additional z-order values. Perhaps this is most easily solved with pointers in the documentation.

@DougBurke
Copy link
Contributor

Thanks for the zindex example - it's now part of the hvega documentation (well, it will be once I get around to releasing 0.4.0.0!). I was reading the VegaLite schema documentation perhaps too literally, as it seemed to focus on 0 and 1 being the main values.

I've changed ZIndex back to being an alias for Natural.

@DougBurke
Copy link
Contributor

One thing I have added is a 'MNoOutliers' constructor for 'MarkProperty' since it looked like the outliers are displayed by default for a boxplot mark, and 'MOutliers []' doesn't turn them off. I'll update this with an example from the new hvega tutorial I've put together (basically a copy of your walk through) once it's released.

@jwoLondon
Copy link
Member Author

Sorry I missed your comment about noOutliers. Have amended so empty lists for maOutliers, maBox, maMedian and maRule remove their respective elements. Have not applied to maTicks as these do not appear by default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants