avatorl / Deneb-Vega-Help

Do you need help with Deneb custom visual for Power BI and/or Vega visualization grammar? Create an issue here to get assistance from Deneb community expert Andrzej Leszkiewicz.
3 stars 0 forks source link

IBCS Bar Chart- Text Y Position at max of AC or PY #2

Closed carlgis closed 4 months ago

carlgis commented 4 months ago

Hi Andrzej, thank you for creating this resource.

I followed your youtube video on creating the IBCS style bar chart in Vega and used it to enhance one of the dashboards I have been working on in PowerBI.

There is one small change I have been trying to make but I am struggling with the syntax.

I'd like for the text mark that displays the AC value to have it's y-position change depending on whether AC is greater than PY or not (ie, if PY is greater than AC then the text should be at the PY y-position).

I tried: "y": {"scale": "yscale", "signal": "max(datum.AC,datum.PY)", "offset": -2} as well as: "y": {"scale": "yscale", "signal": "(datum.AC>datum.PY?datum.AC:datum.PY)", "offset": -2} but both appear to return the max for all values instead of evaluating each data point.

Thanks in advance.

avatorl commented 4 months ago

@carlgis ,

but both appear to return the max for all values instead of evaluating each data point.

They signals inside of "encode" mark property are evaluated for each data point and the syntax of your expressions seem to be correct, therefore something else is affecting the result.

Could you show me your "yscale" scale code and the complete code for both "rect" and "text" marks?

carlgis commented 4 months ago

Sure, I copied the code from your IBCS bar chart example and only edited the text mark.

{
      "name": "yscale",
      "domain": {"data": "table", "field": "AC"},
      "nice": true,
      "range": "height"
    }
{
      "name": "rect-ac",
      "type": "rect",
      "from": {"data": "table"},
      "encode": {
        "enter": {
          "xc": {"scale": "xscale", "field": "month", "band": 0.5},
          "width": {"scale": "xscale", "band": 0.667},
          "y": {"scale": "yscale", "field": "AC"},
          "y2": {"scale": "yscale", "value": 0},
          "fill": {"value": "#333333"}
        }
      }
    }
{
      "type": "text",
      "from": {"data": "rect-ac"},
      "encode": {
        "enter": {
          "align": {"value": "center"},
          "baseline": {"value": "bottom"},
          "fill": {"value": "#333333"},
          "x": {"scale": "xscale", "field": "datum.month", "band": 0.5},
          "y": {"scale": "yscale", "signal": "(datum.AC>datum.PY?datum.AC:datum.PY)", "offset": -2},
          "text": {"field": "datum.AC"},
          "fontSize": {"value": 16}
        }
      }
    }
avatorl commented 4 months ago

Thanks.

There are 2 options:

  1. The "text" mark can be created by using "rect-ac" data table instead of the original "table" data table. "rect-ac" table contains calculated values required for drawing "rect-ac" rectangles, such as "x", "x2", "y", "height", "width", "fill":

image

As you can see, there is also "datum" column in the "rect-ac" table. It contains data from the "table" data table because it was a data source for the "rect-ac".

Therefore, when "rect-ac" is your data table for "text" mark, then to reference AC value from a "signal" property you need to use datum.datum.AC instead of datum.AC

datum.AC references "AC" column, but there is no "AC" column in "rect-ac".

datum.datum.AC references a row in the "rect-ac" table (first datum), then "datum" column in the "rect-ac" table (second "datum"), then "AC" property.

Correct "signal" code is "datum.datum.AC>datum.datum.PY ? datum.datum.AC : datum.datum.PY"

"field": "datum.month" is correct in this case. It references "month" in "datum" column.

  1. The "text" mark can be created using the same data table as the "rect" mark using "from": {"data": "table"} in both "rect" and "text" marks.

    Use "from": {"data": "table"} instead of "from": {"data": "rect-ac"}. In this case you don't need an additional datum (because there is no "datum" column).

    {
      "type": "text",
      "from": {"data": "table"},
      "encode": {
        "enter": {
          "align": {"value": "center"},
          "baseline": {"value": "bottom"},
          "fill": {"value": "#333333"},
          "x": {"scale": "xscale", "field": "month", "band": 0.5},
          "y": {"scale": "yscale", "signal": "(datum.AC>datum.PY?datum.AC:datum.PY)", "offset": -2},
          "text": {"field": "AC"},
          "fontSize": {"value": 16}
        }
      }
    }

Additional I recommend

"domain": {"data": "table", "fields": ["AC","PY"]},

for the scale, to make sure it fits both columns within the "height" range.

carlgis commented 4 months ago

Thank you very much!