vega / vega-lite

A concise grammar of interactive graphics, built on Vega.
https://vega.github.io/vega-lite/
BSD 3-Clause "New" or "Revised" License
4.67k stars 608 forks source link

Browser / renderer inconsistencies #5317

Open jwoLondon opened 5 years ago

jwoLondon commented 5 years ago

Following this twitter thread, there appear to be a number of differences in the way a spec is interpreted between browsers and between renderers. Whether all of these are 'bugs' or 'features' is debatable, but for the record I've isolated the problems:

1. Parsing Dates.

If a string data source representing years is specified as temporal, it can be correctly interpreted as such by Chrome and Safari without the need for an explicit format specification. If the year data field contains a non-integer, Chrome correctly encodes the position (e.g. interpreting 0.5 years as 6 months), but Safari encodes it as zero.

"encoding": {
  "x": {"field": "x", "type": "temporal"},
  "y": {"field": "y", "type": "quantitative"},
  "text": {"field": "name", "type": "nominal"}
},    
"data": {
  "values": [
    {"x": "1675", "y": 76, "name": "CHART"},
    {"x": "1675.5", "y": 76, "name": "CHART"}
  ]
  },
  "mark": {"type": "text"}

If an explicit format is provided, non-integer years are ignored by both Chrome and Safari.

"format": {"parse": {"x": "date:'%Y'"}}

Perhaps this just needs a warning in the documentation against using non-integer values for dates even if they apparently work in some browsers (and more generally, the advice to always specify an explicit parsing format for date-time strings).

2. Missing Data with Line and Area Marks

The following spec that contains 'ragged' data with a missing y-value is displayed as we might expect in Chrome, with an x-domain scale set to the full range of x values [1,4], but the mark shown only for complete x,y pairs [1,3]:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v3.json",
  "data": {
    "values": [ 
      {"x": 1,"y": 10},
      {"x": 2,"y": 8},
      {"x": 3,"y": 6},
      {"x": 4}
    ]
  },
  "encoding": {
    "x": {"field": "x", "type": "quantitative"},
    "y": {"field": "y", "type": "quantitative"}
  },
  "mark": "area"
}
Chrome ragged data

But in Safari, the missing y value is interpreted as the maximum y-domain value:

Safari ragged data

A partial non-data transformation workaround is to constrain the domain and set mark clipping to true, but this can cause problems in layered composite views that may need to share the full [1,4] domain.

{
  "$schema": "https://vega.github.io/schema/vega-lite/v3.json",
  "data": {
    "values": [ 
      {"x": 1,"y": 10},
      {"x": 2,"y": 8},
      {"x": 3,"y": 6},
      {"x": 4}
    ]
  },
  "encoding": {
    "x": {
      "field": "x", 
      "type": "quantitative",
      "scale": { "domain": [1,3]}
    },
    "y": {"field": "y", "type": "quantitative"}
  },
  "mark": {
     "type": "area",
     "clip": true
  }
}

3. Stops Offset Order in Gradient Spec

If order of offsets in a VL4 gradient stops specification has the higher value first, the gradient is not rendered correctly when the renderer is SVG. There is no problem if rendered as Canvas.

{
  "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
  "width": 300,
  "data": {
    "values": [
      {"cat": "a", "value": 10},
      {"cat": "b", "value": 5}
    ]
  },
  "encoding": {
    "x": {"field": "cat", "type": "nominal"},
    "y": {"field": "value", "type": "quantitative"}
  },
  "mark": {
    "type": "bar",
    "color": {
      "gradient": "linear",
      "x1": 0,
      "x2": 1,
      "y1": 1,
      "y2": 1,
      "stops": [
        {"offset": 1, "color": "blue"}, 
        {"offset": 0, "color": "red"}]
    }
  }
}

While the workaround is simply to ensure that the order of offsets in the stops array is from low to high (i.e. with the red line before the blue line in example above), this is unintuitive behaviour and not obvious to spot if testing with a Canvas renderer.

domoritz commented 5 years ago

Thank you for filing the issues! Let's split them into separate issues so that we can decide for each whether they need to be fixed here or in Vega.

jheer commented 5 years ago

Thanks @jwoLondon!

  1. Dates are a known source of cross-browser issues. In particular, if no format is provided, Vega defaults to Date.parse, which varies across vendors. Your conclusion about providing and adhering to known date formats is good advice. Beyond that, I don't think there are any bugs to fix here. A longer-term feature request might be to abandon Date.parse and build out our own standardized sets of date formats to apply as defaults... though that might prove painful.

  2. We will need to investigate why we're seeing different "imputations" of the undefined y value. Looks like a Vega-level issue, and a potential bug to fix!

  3. The gradient stops are assumed to be provided in ascending order, though I wouldn't be surprised if this is not sufficiently documented. At the Vega level we can consider adding a sort step prior to Canvas/SVG gradient generation. Feel free to file an enhancement issue.

Thanks again!