Deston
Deston

Reputation: 97

Text mark (data label) placement in a layered Vega-Lite chart

I am attempting to exercise greater control in the placement of text marks within a chart that has dual Y-Axis; however, applying an independent scale throws the text mark placement out of kilter.

Here is an example of the intended text mark placement in a stacked chart:

intended output

This is what I am getting at the moment:

unwanted output

This is the specification I am using:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {
        "Month": 1,
        "Category": "Bikes",
        "Sales": 100,
        "Sales LY": 90,
        "Target": 95,
        "Volume": 300
      },
      {
        "Month": 1,
        "Category": "Cars",
        "Sales": 560,
        "Sales LY": 800,
        "Target": 880,
        "Volume": 1200
      },
      {
        "Month": 2,
        "Category": "Bikes",
        "Sales": 130,
        "Sales LY": 170,
        "Target": 190,
        "Volume": 450
      },
      {
        "Month": 2,
        "Category": "Cars",
        "Sales": 600,
        "Sales LY": 665,
        "Target": 680,
        "Volume": 1200
      },
      {
        "Month": 3,
        "Category": "Bikes",
        "Sales": 200,
        "Sales LY": 150,
        "Target": 165,
        "Volume": 400
      },
      {
        "Month": 3,
        "Category": "Cars",
        "Sales": 750,
        "Sales LY": 1000,
        "Target": 1100,
        "Volume": 1200
      },
      {
        "Month": 4,
        "Category": "Bikes",
        "Sales": 80,
        "Sales LY": 105,
        "Target": 120,
        "Volume": 500
      },
      {
        "Month": 4,
        "Category": "Cars",
        "Sales": 800,
        "Sales LY": 600,
        "Target": 660,
        "Volume": 1200
      }
    ]
  },
    "transform": [
      {"calculate": "'Volume'", "as": "Volume Legend"},        
      {"calculate": "'Target'", "as": "Target Legend"},      
      {"calculate": "datum.Category + ' LY'", "as": "Category2"}             
      ] ,
  "height": 300,
  "width": 300,  
  "layer": [
    {
      "name": "SALES",
      "mark": {"type": "bar", "xOffset": 0, "size": 10},
      "encoding": {
        "x": {"field": "Month", "type": "ordinal", "axis": {"labelAngle": 0}},
        "y": {"field": "Sales", "type": "quantitative"},
          "color": {
        "field": "Category",             
          "type" : "nominal",          
            "scale": {
            "domain": ["Bikes","Cars" ],
          "range": ["#4CD964","#39A34B"]}
        }
      }
    },
    {
      "name": "SALES Data Labels",
      "mark": {
        "type": "text", 
        "align": "right", 
        "baseline": "line-bottom",               
        "dx": 10
          },      
      "encoding": {
        "x": {"field": "Month", "type": "ordinal"},        
        "y": {"field": "Sales", "type": "quantitative", "axis": null},
        "text": {"field": "Sales","type": "quantitative"} 
      }
    },
    {
      "name": "VOLUME",
      "mark": {"type": "line"},
      "encoding": {
        "x": {
          "field": "Month",
          "type": "ordinal"
        },
        "y": {
          "aggregate": "sum",
          "field": "Volume",
          "type": "quantitative"
        },
        "stroke": {
          "field": "Volume Legend",
          "scale": {"range": ["black"]},
          "legend": {"title": ""}
        }
      }
    }
  ],
  "resolve": {
    "scale": {"y": "independent"}
  }
}

What modifications to the script can be made to achieve the desired outcome? Any assistance would be greatly appreciated!!

Upvotes: 1

Views: 946

Answers (1)

davidebacci
davidebacci

Reputation: 30219

You mean like this? You can have layers inside layers to isolate the resolve attribute.

enter image description here

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      {
        "Month": 1,
        "Category": "Bikes",
        "Sales": 100,
        "Sales LY": 90,
        "Target": 95,
        "Volume": 300
      },
      {
        "Month": 1,
        "Category": "Cars",
        "Sales": 560,
        "Sales LY": 800,
        "Target": 880,
        "Volume": 1200
      },
      {
        "Month": 2,
        "Category": "Bikes",
        "Sales": 130,
        "Sales LY": 170,
        "Target": 190,
        "Volume": 450
      },
      {
        "Month": 2,
        "Category": "Cars",
        "Sales": 600,
        "Sales LY": 665,
        "Target": 680,
        "Volume": 1200
      },
      {
        "Month": 3,
        "Category": "Bikes",
        "Sales": 200,
        "Sales LY": 150,
        "Target": 165,
        "Volume": 400
      },
      {
        "Month": 3,
        "Category": "Cars",
        "Sales": 750,
        "Sales LY": 1000,
        "Target": 1100,
        "Volume": 1200
      },
      {
        "Month": 4,
        "Category": "Bikes",
        "Sales": 80,
        "Sales LY": 105,
        "Target": 120,
        "Volume": 500
      },
      {
        "Month": 4,
        "Category": "Cars",
        "Sales": 800,
        "Sales LY": 600,
        "Target": 660,
        "Volume": 1200
      }
    ]
  },
  "transform": [
    {"calculate": "'Volume'", "as": "Volume Legend"},
    {"calculate": "'Target'", "as": "Target Legend"},
    {"calculate": "datum.Category + ' LY'", "as": "Category2"}
  ],
  "height": 300,
  "width": 300,
  "encoding": {
    "x": {"field": "Month", "type": "ordinal", "axis": {"labelAngle": 0}},
    "y": {"field": "Sales", "type": "quantitative"}
  },
  "layer": [
    {
      "layer": [
        {
          "name": "SALES",
          "mark": {"type": "bar", "xOffset": 0, "size": 10},
          "encoding": {
            "color": {
              "field": "Category",
              "type": "nominal",
              "scale": {
                "domain": ["Bikes", "Cars"],
                "range": ["#4CD964", "#39A34B"]
              }
            }
          }
        },
        {
          "name": "SALES Data Labels",
          "mark": {
            "type": "text",
            "align": "center",
            "baseline": "line-bottom"
          },
          "encoding": {"text": {"field": "Sales", "type": "quantitative"}}
        }
      ]
    },
    {
      "name": "VOLUME",
      "mark": {"type": "line"},
      "encoding": {
        "x": {"field": "Month", "type": "ordinal"},
        "y": {"aggregate": "sum", "field": "Volume", "type": "quantitative"},
        "stroke": {
          "field": "Volume Legend",
          "scale": {"range": ["black"]},
          "legend": {"title": ""}
        }
      }
    }
  ],
  "resolve": {"scale": {"y": "independent"}}
}

Upvotes: 1

Related Questions