Search code examples
vega-lite

Data-layout, layers and legends in vega-lite


I have a very simple situation, and I believe my solution is too complicated and there's a good chance I'm missing something. Say I have measures of time, positions (x,y,z), angles (roll, pitch, yaw) and speed. I want a simple visualization like I currently have where the speed plot can be used as "brush" to zoom dynamically into the first two graphs.

enter image description here

A small example of my plot in the vega-editor can be found here.

1. Can I use a different data-layout?

Right now, each point is an object

{
    "pitch": -0.006149084584096612,
    "roll": 0.0007914191778949736,
    "speed": 4.747345444390669,
    "time": 0.519741,
    "x": -0.01731604791076788,
    "y": 0.020068310429957575,
    "yaw": 0.0038123065311157552,
    "z": -0.016005977140476142
}

With many data-points, this is a lot of memory just for repeating column names. Much better would be to have the data in the form

{
    "time": [t1, t2, t3, ...],
    "x": [...],
    ...
}

but vega's "row first" representation doesn't allow for that. I already asked on Slack where someone suggested to use Fold and Pivot, but I'm not sure how to implement this. Is it possible to use data that are stored as arrays? I'm creating the data myself from a C++ program and I'm free to export a different representation easily. The only question is how do I make vega-lite understand?

2. Layers and legends.

If I had time-series data with an "indicator column", I could create plots that combine several graphs easily. Unfortunately, I don't have that and the only solution I found is to use layers. With this, I have to set the colours for different graphs explicitly (instead of using schemes) and I don't get a legend.

If layers are really to only option here to combine, e.g. x,y,z into one "Movement" plot, how can I get a legend for this plot that tells me red -> x, green -> y, and blue -> z?


Solution

  • The answer is "yes" to both of your questions.

    The key to the first question is to pass the data in a dense format and use the Flatten Transform to expand it.

    The key to the second question is to use a Fold Transform to turn multiple columns into an indicator plus a value.

    Here is a demonstration of this for a single chart (open in editor):

    {
      "data": {
        "values": [
          {
            "time": [1, 2, 3, 4],
            "x": [5, 4, 5, 2],
            "y": [2, 3, 2, 4],
            "z": [1, 2, 1, 0]
          }
        ]
      },
      "transform": [
        {"flatten": ["time", "x", "y", "z"]},
        {"fold": ["x", "y", "z"], "as": ["column", "value"]}
      ],
      "mark": "line",
      "encoding": {
        "x": {"field": "time", "type": "quantitative"},
        "y": {"field": "value", "type": "quantitative"},
        "color": {"field": "column", "type": "nominal"}
      }
    }
    

    enter image description here