Search code examples
javascriptarraysdata-visualizationvega-lite

Setting a field to an object in an array, Vega-lite


I have an array of objects that I am using as a dataset in an interactive data dashboard. I want to add a new feature that displays data from only one object at a time, rather than pulling data from all objects (which I am already doing and it works well). As a test case, I have created a simple array:

var test1 = [
  [{
    "name": "Piece One",
    "amount": 5
  }, {
    "name": "Piece Two",
    "amount": 5
  }, {
    "name": "Piece Three",
    "amount": 5
  }],
  [{
    "name": "Piece One",
    "amount": 1
  }, {
    "name": "Piece Two",
    "amount": 1
  }, {
    "name": "Piece Three",
    "amount": 5
  }]
];

and the Vega-lite javascript:

var pieCreate = {
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "title": "A pie chart",
  "description": "A simple pie chart with embedded data.",
  "width": "container",
  "height": "container",
  "data": {
    "values": test1[0]
  },
  "mark": "arc",
  "encoding": {
    "theta": {
      "field": "amount",
      "type": "quantitative"
    },
    "color": {
      "field": "name",
      "type": "nominal",
      "legend": null
    }
  }
};

This works, but I want the user to be able to choose which object to display (in the dashboard, each object contains data on different schools, and I want the user to be able to choose which school's data to display using a dropdown menu). My first thought was to set up a signal in the "data": {"values": field that would change the number in brackets to the array I want, but after a lot of trial and error, I think that may be a dead end. Signals should work to modify "field": "amount" and "field": "name" but I've tried every iteration of [0].amount that I can think of, while dropping the brackets from test1[0] and nothing has worked. If I can manage to access the object by directly referencing it in "field": I believe I can figure out the process using a signal and html form, but I'm starting to doubt if I'm even on the right track here.

I also tried the process outlined here in the vega-lite documentation: https://vega.github.io/vega-lite/tutorials/streaming.html, but it's doing something much more complicated than what I'm trying to do, and my javascript knowledge isn't sufficient to break it down to something usable. Does anyone have any ideas on how to make this work, using any of the above approaches (or a new, better one)?


Solution

  • You can use the vega Api's to change the data. On your selection, add a change event and on some conditions you can toggle between your data using those API's. Refer the below snippet or fiddle:

    var test1 = [
      [{
        "name": "Piece One",
        "amount": 5
      }, {
        "name": "Piece Two",
        "amount": 5
      }, {
        "name": "Piece Three",
        "amount": 5
      }],
      [{
        "name": "Piece One",
        "amount": 1
      }, {
        "name": "Piece Two",
        "amount": 1
      }, {
        "name": "Piece Three",
        "amount": 5
      }]
    ];
    
    var yourVlSpec = {
      "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
      "title": "A pie chart",
      "description": "A simple pie chart with embedded data.",
      "width": "350",
      "height": "400",
      "data": {
        "values": test1[0]
      },
      "mark": "arc",
      "encoding": {
        "theta": {
          "field": "amount",
          "type": "quantitative"
        },
        "color": {
          "field": "name",
          "type": "nominal",
          "legend": null
        }
      }
    }
    var view;
    vegaEmbed("#vis", yourVlSpec).then(res => {
      view = res.view;
    });
    
    function handleChange(a, b) {
      var selectValue = document.getElementById("myselect").value;
      if (selectValue == 'A') {
        view.data('source_0', test1[0]);
      } else {
        view.data('source_0', test1[1]);
      }
      view.runAsync();
    }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/vega.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/vega-lite.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/build/vega-embed.min.js"></script>
    
    <select id="myselect" style="width:100px;" onchange="handleChange()">
      <option>A</option>
      <option>B</option>
    </select>
    <br>
    <div id="vis"></div>