deneb-viz / deneb

Deneb is a custom visual for Microsoft Power BI, which allows developers to use the declarative JSON syntax of the Vega or Vega-Lite languages to create their own data visualizations.
https://deneb-viz.github.io
MIT License
180 stars 15 forks source link

Difference in Behaviour Between Online Editor and Deneb #417

Open PBI-David opened 7 months ago

PBI-David commented 7 months ago

Using Deneb standalone (Deneb_STANDALONE.1.6.2.20231207.0bcb9c6.pbiviz), the following spec produces an error but renders correctly in the online editor:

image

{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "autosize": {"type": "fit-x", "contains": "padding"},
  "background": "white",
  "padding": 5,
  "height": 250,
  "style": "cell",
  "data": [
    {
      "name": "source_0",
      "url": "https://vega.github.io/editor/data/cars.json",
      "format": {"type": "json"},
      "transform": [
        {
          "type": "aggregate",
          "groupby": ["Origin"],
          "ops": ["count"],
          "fields": [null],
          "as": ["__count"]
        }
      ]
    }
  ],
  "signals": [
    {
      "name": "width",
      "init": "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
      "on": [
        {
          "update": "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
          "events": "window:resize"
        }
      ]
    }
  ],
  "marks": [
    {
      "name": "marks",
      "type": "rect",
      "style": ["bar"],
      "from": {"data": "source_0"},
      "encode": {
        "update": {
          "fill": {"value": "#4c78a8"},
          "ariaRoleDescription": {"value": "bar"},
          "description": {
            "signal": "\"Origin: \" + (isValid(datum[\"Origin\"]) ? datum[\"Origin\"] : \"\"+datum[\"Origin\"]) + \"; Number of Cars: \" + (format(datum[\"__count\"], \"\"))"
          },
          "x": {"scale": "x", "field": "Origin"},
          "width": {"signal": "max(0.25, bandwidth('x'))"},
          "y": {"scale": "y", "field": "__count"},
          "y2": {"scale": "y", "value": 0}
        }
      }
    }
  ],
  "scales": [
    {
      "name": "x",
      "type": "band",
      "domain": {"data": "source_0", "field": "Origin", "sort": true},
      "range": [0, {"signal": "width"}],
      "paddingInner": 0.1,
      "paddingOuter": 0.05
    },
    {
      "name": "y",
      "type": "linear",
      "domain": {"data": "source_0", "field": "__count"},
      "range": [{"signal": "height"}, 0],
      "nice": true,
      "zero": true
    }
  ],
  "axes": [
    {
      "scale": "y",
      "orient": "left",
      "gridScale": "x",
      "grid": true,
      "tickCount": {"signal": "ceil(height/40)"},
      "domain": false,
      "labels": false,
      "aria": false,
      "maxExtent": 0,
      "minExtent": 0,
      "ticks": false,
      "zindex": 0
    },
    {
      "scale": "x",
      "orient": "bottom",
      "grid": false,
      "title": "Origin",
      "labelAlign": "right",
      "labelAngle": 270,
      "labelBaseline": "middle",
      "zindex": 0
    },
    {
      "scale": "y",
      "orient": "left",
      "grid": false,
      "title": "Number of Cars",
      "labelOverlap": true,
      "tickCount": {"signal": "ceil(height/40)"},
      "zindex": 0
    }
  ]
}

Link

In Deneb:

image

dm-p commented 6 months ago

Looks like Vega Editor is on Vega 5.25.0, but we're on 5.26.1. I'll have to find some time to rebuild Deneb with the older version to see if it's something to do with that, or if there's some other forces at work with how we're patching or parsing the spec in Deneb.

PBI-David commented 3 months ago

Just an FYI that I'm running into this elsewhere too.

dm-p commented 3 months ago

To confirm, does "elsewhere" mean for other examples using Deneb or elsewhere in the Vega ecosystem?

Interim notes for me: I've had a quick look, and this seems to be an issue in both legacy builds and the newer versions (>= 1.6, which uses the revised parse/build workflow, and 1.7, which uses a further refinement to handle JSONC). The versions of Vega are in sync on 1.7 and Vega Editor currently also.

If we disable the explicit parse during spec processing and patching, Vega still fires this when the view initializes, so there doesn't seem to be any hacking around it to see if the spec will even render as it does in Vega editor.

For when I get a chance to pull on the thread some more, this is where the error is being raised in Vega.

PBI-David commented 3 months ago

This Vega spec code (generated from VL) works fine in the online editor but causes the issue in Deneb.


{
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "Dataviz by Dav Bacci",
  "autosize": {"type": "fit", "contains": "padding"},
  "background": "#222431",
  "padding": 30,
  "style": "cell",
  "data": [
    {
      "name": "source_0",
      "values": [
        {"a": "A", "val": 14},
        {"a": "B", "val": 17},
        {"a": "C", "val": 13},
        {"a": "D", "val": 19},
        {"a": "E", "val": 33},
        {"a": "F", "val": 29},
        {"a": "G", "val": 31},
        {"a": "H", "val": 26},
        {"a": "I", "val": 23},
        {"a": "J", "val": 19},
        {"a": "K", "val": 25},
        {"a": "L", "val": 21},
        {"a": "M", "val": 19},
        {"a": "N", "val": 14},
        {"a": "O", "val": 17},
        {"a": "P", "val": 12}
      ]
    },
    {
      "name": "data_0",
      "source": "source_0",
      "transform": [
        {"type": "formula", "expr": "sequence(0,40)", "as": "sequence"},
        {"type": "formula", "expr": "sequence(0,datum.val)", "as": "sequence2"},
        {
          "type": "flatten",
          "fields": ["sequence", "sequence2"],
          "as": ["sequence", "sequence2"]
        },
        {"type": "formula", "expr": "1", "as": "b"},
        {"type": "formula", "expr": "datum.sequence2 ==null? null:1", "as": "c"}
      ]
    },
    {
      "name": "data_1",
      "source": "data_0",
      "transform": [
        {
          "type": "stack",
          "groupby": ["a"],
          "field": "b",
          "sort": {"field": [], "order": []},
          "as": ["b_start", "b_end"],
          "offset": "zero"
        },
        {
          "type": "filter",
          "expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"])"
        }
      ]
    },
    {
      "name": "data_2",
      "source": "data_0",
      "transform": [
        {
          "type": "stack",
          "groupby": ["a"],
          "field": "c",
          "sort": {"field": [], "order": []},
          "as": ["c_start", "c_end"],
          "offset": "zero"
        },
        {
          "type": "filter",
          "expr": "isValid(datum[\"c\"]) && isFinite(+datum[\"c\"])"
        }
      ]
    }
  ],
  "signals": [
    {
      "name": "width",
      "init": "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
      "on": [
        {
          "update": "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
          "events": "window:resize"
        }
      ]
    },
    {
      "name": "height",
      "init": "isFinite(containerSize()[1]) ? containerSize()[1] : 200",
      "on": [
        {
          "update": "isFinite(containerSize()[1]) ? containerSize()[1] : 200",
          "events": "window:resize"
        }
      ]
    }
  ],
  "marks": [
    {
      "name": "layer_0_marks",
      "type": "rect",
      "style": ["bar"],
      "from": {"data": "data_1"},
      "encode": {
        "update": {
          "stroke": {"value": "#222431"},
          "strokeWidth": {"value": 3},
          "fill": {"value": "#3f424e"},
          "ariaRoleDescription": {"value": "bar"},
          "description": {
            "signal": "\"a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; b: \" + (format(datum[\"b\"], \"\"))"
          },
          "x": {"scale": "x", "field": "a"},
          "width": {"signal": "max(0.25, bandwidth('x'))"},
          "y": {"scale": "y", "field": "b_end"},
          "y2": {"scale": "y", "field": "b_start"}
        }
      }
    },
    {
      "name": "layer_1_marks",
      "type": "rect",
      "style": ["bar"],
      "from": {"data": "data_2"},
      "encode": {
        "update": {
          "stroke": {"value": "#222431"},
          "strokeWidth": {"value": 3},
          "fill": {"scale": "color", "field": "a"},
          "ariaRoleDescription": {"value": "bar"},
          "description": {
            "signal": "\"a: \" + (isValid(datum[\"a\"]) ? datum[\"a\"] : \"\"+datum[\"a\"]) + \"; c: \" + (format(datum[\"c\"], \"\"))"
          },
          "x": {"scale": "x", "field": "a"},
          "width": {"signal": "max(0.25, bandwidth('x'))"},
          "y": {"scale": "y", "field": "c_end"},
          "y2": {"scale": "y", "field": "c_start"}
        }
      }
    }
  ],
  "scales": [
    {
      "name": "x",
      "type": "band",
      "domain": {
        "fields": [
          {"data": "data_1", "field": "a"},
          {"data": "data_2", "field": "a"}
        ],
        "sort": true
      },
      "range": [0, {"signal": "width"}],
      "paddingInner": 0.1,
      "paddingOuter": 0
    },
    {
      "name": "y",
      "type": "linear",
      "domain": {
        "fields": [
          {"data": "data_1", "field": "b_start"},
          {"data": "data_1", "field": "b_end"},
          {"data": "data_2", "field": "c_start"},
          {"data": "data_2", "field": "c_end"}
        ]
      },
      "range": [{"signal": "height"}, 0],
      "nice": true,
      "zero": true
    },
    {
      "name": "color",
      "type": "ordinal",
      "domain": {"data": "data_2", "field": "a", "sort": true},
      "range": {"scheme": "sinebow"}
    }
  ],
  "config": {"style": {"cell": {"stroke": "transparent"}}}
}
PBI-David commented 3 months ago

It seems to happen when I see a VL spec, generate the Vega code and then try and use that.

dm-p commented 3 months ago

Thanks for the additional info - I'll try to see if I can zero-in on what's going on as soon as I get the bandwidth