vega

Helper for working with Vega-Lite (and Vega) within iJavaScript notebooks.

(Vega-Lite-Api: creates -> Vega-Lite JSON specifications: creates -> Vega charting specifications: using -> D3 as a visualization kernel)

For example, this is a very simple demonstration for writing a vega-lite chart (the simplest way to get started)

 simpleData = [{fruit:'Apples',yield:20,year:'2020'},{fruit:'Apples',yield:22,year:'2021'},
   {fruit:'Bananas',yield:15,year:'2020'},{fruit:'Bananas',yield:12,year:'2021'},
   {fruit:'Pears',yield:18,year:'2020'},{fruit:'Pears',yield:19,year:'2021'}];
 
 utils.vega.svg(
 // accept the reference to the vega-lite instance passed
 (vl) => vl
   // render as points
   .markPoint()
       // use simpleData as the data source
       .data(simpleData)
       // title
       .title('Fruit by Yield')
       .width(100)
       .encode(
           // define the x axis as the Qualitative / Numerical 'yield' property
           vl.y().fieldQ('yield'),
           // define the y axis as the Nominative / TextBased 'fruit' property
           vl.x().fieldN('fruit'),
           // define the color series based on the Qualitative / Numerical 'year' property
           vl.color().fieldN('year')
       )
 );

Screenshot

and with simple changes, convert it to a bar graph

Screenshot

What is Vega-Lite / Vega-Lite-API?

Vega-Lite is a charting library that provides a great deal of flexibility and interaction while also allowing for very simple use cases
(and further simplified with Vega-Lite-Api)

Screenshot of vega lite examples from vega-lite home

It is built on Vega that uses d3 as a visualization kernel.

Note that Vega-Lite is supported by two options within this library:

(Where svg renders directly in Jupyter, and embed uses ijs.htmlScript() to render)

Note that rendering in the browser (as html / javascript), will provide more interactivity options (like export options) while also having consequences in exporting the notebook in some cases.

What is Vega?

True Vega is also supported, providing support for additional capabilities (that to my knowledge cannot be done with vega-lite) such as Radar Charts, Contour Plots, Tree Layouts, Force Plots, and others.

However Vega does not have a JavaScript API:

Screenshot of Vega Charts

In the context of Notebooks - is expected that Vega-Lite will be sufficient for most cases.

Embedding vs SVG

SVG versions of charts render directly within Jupyter Notebook (as svg output)

(As a rule - embed... calls and svg... calls can be easily interchanged)

Embedding means the charts run within the browser (through dynamic HTML in the output).

This provides greater flexibility (at the consequence of complexity of splitting computation between jupyter and browser)

As opposed to the SVG version, we can now:

  • use vega-embed allowing for downloading of the chart

Screenshot of Vega-Embed;

  • support for interactions and interactive dashboards
utils.vega.svgFromSpec({
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {"url": "https://vega.github.io/vega-lite/examples/data/sp500.csv"},
  "vconcat": [{
    "width": 480,
    "mark": "area",
    "encoding": {
      "x": {
        "field": "date",
        "type": "temporal",
        "scale": {"domain": {"param": "brush"}},
        "axis": {"title": ""}
      },
      "y": {"field": "price", "type": "quantitative"}
    }
  }, {
    "width": 480,
    "height": 60,
    "mark": "area",
    "params": [{
      "name": "brush",
      "select": {"type": "interval", "encodings": ["x"]}
    }],
    "encoding": {
      "x": {
        "field": "date",
        "type": "temporal"
      },
      "y": {
        "field": "price",
        "type": "quantitative",
        "axis": {"tickCount": 3, "grid": false}
      }
    }
  }]
});

Screenshot of interactive charts

  • support for tooltips within the Jupyter cell
utils.vega.embedFromSpec({
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A scatterplot showing horsepower and miles per gallons that opens a Google search for the car that you click on.",
  "data": {"url": "https://vega.github.io/vega-lite/examples/data/cars.json"},
  "height": 600,
  "width": 400,
  "mark": "point",
  "transform": [{
    "calculate": "'https://www.google.com/search?q=' + datum.Name", "as": "url"
  }],
  "encoding": {
    "x": {"field": "Horsepower", "type": "quantitative"},
    "y": {"field": "Miles_per_Gallon", "type": "quantitative"},
    "color": {"field": "Origin", "type": "nominal"},
    //-- simply by adding the tooltip encoding here
    "tooltip": {"field": "Name", "type": "nominal"},
    "href": {"field": "url", "type": "nominal"}
  }
});

Screenshot for tooltips

or through the vega lite


FAQ

The following are a series of common questions / issues, put here for visibility.

Passing Objects to vega-lite-api

Note that there are some things that are not supported by the vega-lite-api
(such as grouping)

This is only a problem with the vega-lite-api, as it writes the spec used for vega-lite

In these cases, you can send an object within many of the methods, as it no longer needs to translate how that object should look.

(like sending mark( type:'bar') instead of .markBar() - to allow for tooltips
or passing an object to encode to support grouping)

simpleData = [{fruit:'Apples',yield:20,year:'2020'},{fruit:'Apples',yield:22,year:'2021'},
  {fruit:'Bananas',yield:15,year:'2020'},{fruit:'Bananas',yield:12,year:'2021'},
  {fruit:'Pears',yield:18,year:'2020'},{fruit:'Pears',yield:19,year:'2021'}];
 
utils.vega.svg((vl) => vl
  // render as points
  .mark({ type: 'bar', tooltip: true})
  .data(simpleData)
  .title('Fruit by Yield')
  .width(100)
  .encode({
    "x": {"field": "fruit"},
    "y": {"field": "yield", "type": "quantitative"},
    "xOffset": {"field": "year"},
    "color": {"field": "year"}
  })
);

Screenshot


Chart Series

Instead of grouping values, you can also create a series of charts instead.

utils.vega.svg((vl) => vl
  // render as points
  .mark({ type: 'arc', innerRadius: 30, tooltip: true})
      .data(simpleData)
      .title('Fruit by Yield')
      .width(100)
      .encode(
        // define the arc on the graph with the Qualitative / Numerical 'yield' property
        vl.theta().fieldQ('yield'),
        // define the y axis as the based on the Qualitative / Numerical 'year' property
        vl.color().fieldN('year'),
        // define the color series Nominative / TextBased 'fruit' property
        vl.column().fieldN('fruit')
      )
);

Screenshot

Other examples can be found under the vega-lite examples and rendered with svgFromSpec or embedFromSpec


Object Formatting / Conversion

Note that vega-lite examples use data at the mark level:

[{fruit:'Apples',yield:20,year:'2020'},{fruit:'Apples',yield:22,year:'2021'},
  {fruit:'Bananas',yield:15,year:'2020'},{fruit:'Bananas',yield:12,year:'2021'},
  {fruit:'Pears',yield:18,year:'2020'},{fruit:'Pears',yield:19,year:'2021'}];

not at the series level:

[{ year:'2020', apples:20, bananas:15, pears:18 },
 { year:'2021', apples:22, bananas:12, pears:19 }];

If your data is at the series level, you can:

  • Transform the data with the group.separateByFields
    • utils.group.separateByFields(fruitSeriesData, 'apples', 'bananas', 'pears');
    • this makes a new field called 'key' that will have values of either apples, bananas or pears
  • or using the vega-lite fold transform
    • by adding in the .transform() into the spec - like below
fruitSeriesData = [{ year:'2020', apples:20, bananas:15, pears:18 },
  { year:'2021', apples:22, bananas:12, pears:19 }];

utils.vega.svg((vl) => vl
  .mark({ type: 'arc', innerRadius: 30, tooltip: true})
    .data(fruitSeriesData)

    //-- apples, bananas and pears will now be separate records
    //-- with the new `key` field as either 'apple', 'banana', or 'pears'
    //-- and the new `value` field storing the value of those fields.
    .transform([{ fold: ['apples', 'bananas', 'pears']}])

    .title('Fruit by Yield')
    .width(100)
    .encode(
      // define the arc on the graph with the Qualitative / Numerical 'yield' property
      vl.theta().fieldQ('value'),
      // define the y axis as the Nominative / TextBased 'fruit' property
      vl.color().fieldN('year'),
      // define the color series based on the Qualitative / Numerical 'year' property
      vl.column().fieldN('key')
    )
)

Screenshot


For more:

Methods

(static) embed(fn, display)

Renders a vega-lite diagram within ijs.htmlScript (browser).

Unlike vega.svg() - this renders with ijs.htmlScript (html)

Please note that svg... and embed... calls are meant to be easily interchangable.

vl.embed((vl) => vl.markCircle()
  .title('Binned Rotten Tomatoes Rating by IMDB Rating')
  .data(movies)
  .encode(
    vl.x().fieldQ('Rotten Tomatoes Rating').bin({maxbins: 20}),
    vl.y().fieldQ('IMDB Rating').bin({maxbins: 20}),
    vl.size().count()
  ));

Screenshot of embed

See the Vega-Lite tutorial.

Parameters:
Name Type Description
fn function

function of type (vl) => {encodedVegaLite) that returns the vega lite instance encoded for a graph

Properties
Name Type Description
vl VegaLiteInstance

Parameter: The Vega Lite instance

display Display

the iJavaScript Display. (Note: $$ refers to the current display within the iJavaScript kernel) See the NEL documentation for more

(static) embedFromSpec(vegaSpec, display)

Renders a vega-lite chart from a JSON / Object specification.

Unlike vega.svgFromSpec() - this renders with ijs.htmlScript (html)

You can either pass directly the Schema Objects (ex: parsed JSON from the vega lite examples)

Such as this one for bar charts

sampleData = [
  {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
  {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
  {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
];
utils.vega.embedFromSpec(
{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": sampleData
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
    "y": {"field": "b", "type": "quantitative"}
  }
});

Screenshot of object schema

... or the strings directly from the vega lite examples.

utils.vega.embedFromSpec(`
{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A simple bar chart with embedded data.",
  ...
}`)
Parameters:
Name Type Description
vegaSpec String

Vega string specification

display Display

the iJavaScript display

(static) embedFromVegaSpec(spec)

Renders an Vega (not Vega-lite) chart from a JSON / Object specification.

Unlike vega.svgFromVegaSpec() - this renders with ijs.htmlScript (html)

Similar to vega.svgFromSpec(), the specification can either be an object or JSON encoded string.

This example is from the Vega Line Chart example

utils.vega.embedFromVegaSpec({
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "A basic line chart example.",
  "width": 500,
  "height": 200,
  "padding": 5,

  "signals": [
    {
      "name": "interpolate",
      "value": "linear",
      "bind": {
        "input": "select",
        "options": [
          "basis",
          "cardinal",
          "catmull-rom",
          "linear",
          "monotone",
          "natural",
          "step",
          "step-after",
          "step-before"
        ]
      }
    }
  ],

  "data": [
    {
      "name": "table",
      "values": [
        {"x": 0, "y": 28, "c":0}, {"x": 0, "y": 20, "c":1},
        {"x": 1, "y": 43, "c":0}, {"x": 1, "y": 35, "c":1},
        {"x": 2, "y": 81, "c":0}, {"x": 2, "y": 10, "c":1},
        {"x": 3, "y": 19, "c":0}, {"x": 3, "y": 15, "c":1},
        {"x": 4, "y": 52, "c":0}, {"x": 4, "y": 48, "c":1},
        {"x": 5, "y": 24, "c":0}, {"x": 5, "y": 28, "c":1},
        {"x": 6, "y": 87, "c":0}, {"x": 6, "y": 66, "c":1},
        {"x": 7, "y": 17, "c":0}, {"x": 7, "y": 27, "c":1},
        {"x": 8, "y": 68, "c":0}, {"x": 8, "y": 16, "c":1},
        {"x": 9, "y": 49, "c":0}, {"x": 9, "y": 25, "c":1}
      ]
    }
  ],

  "scales": [
    {
      "name": "x",
      "type": "point",
      "range": "width",
      "domain": {"data": "table", "field": "x"}
    },
    {
      "name": "y",
      "type": "linear",
      "range": "height",
      "nice": true,
      "zero": true,
      "domain": {"data": "table", "field": "y"}
    },
    {
      "name": "color",
      "type": "ordinal",
      "range": "category",
      "domain": {"data": "table", "field": "c"}
    }
  ],

  "axes": [
    {"orient": "bottom", "scale": "x"},
    {"orient": "left", "scale": "y"}
  ],

  "marks": [
    {
      "type": "group",
      "from": {
        "facet": {
          "name": "series",
          "data": "table",
          "groupby": "c"
        }
      },
      "marks": [
        {
          "type": "line",
          "from": {"data": "series"},
          "encode": {
            "enter": {
              "x": {"scale": "x", "field": "x"},
              "y": {"scale": "y", "field": "y"},
              "stroke": {"scale": "color", "field": "c"},
              "strokeWidth": {"value": 2}
            },
            "update": {
              "interpolate": {"signal": "interpolate"},
              "strokeOpacity": {"value": 1}
            },
            "hover": {
              "strokeOpacity": {"value": 0.5}
            }
          }
        }
      ]
    }
  ]
});

Screenshot of vega schema chart

Parameters:
Name Type Description
spec String | Object

Vega specification

(static) svg(fn, display)

Renders a svg of a vega lite diagram directly within Jupyter

Unlike vega.embed() - this renders directly within Jupyter.

vl.svg((vl) => vl.markCircle()
  .title('Binned Rotten Tomatoes Rating by IMDB Rating')
  .data(movies)
  .encode(
    vl.x().fieldQ('Rotten Tomatoes Rating').bin({maxbins: 20}),
    vl.y().fieldQ('IMDB Rating').bin({maxbins: 20}),
    vl.size().count()
  ));

Screenshot of Binned Vega Chart

See the Vega-Lite tutorial.

Parameters:
Name Type Description
fn function

function of type (vl) => {encodedVegaLite) that returns the vega lite instance encoded for a graph

Properties
Name Type Description
vl VegaLiteInstance

Parameter: The Vega Lite instance

display Display

the iJavaScript Display. (Note: $$ refers to the current display within the iJavaScript kernel) See the NEL documentation for more

(static) svgFromSpec(vegaSpec, display)

Renders a vega-lite chart from a JSON / Object specification.

Unlike vega.embedFromSpec() - this renders directly within Jupyter.

Such as this one for bar charts from the vega lite examples

You can either pass the Schema as:

  • parsed JSON Objects (allowing for sending NodeJS data and config)
  • or as a JSON encoded string

Parsed JSON

sampleData = [
  {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
  {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
  {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
];
utils.vega.svgFromSpec(
{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": sampleData
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
    "y": {"field": "b", "type": "quantitative"}
  }
});

Screenshot of object schema

  • JSON encoded String
utils.vega.svgFromSpec(`
{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": [
      {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
      {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
      {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
    "y": {"field": "b", "type": "quantitative"}
  }
}`)

Screenshot of the string parsed

Parameters:
Name Type Description
vegaSpec String

Vega string specification

display Display

the iJavaScript display

(static) svgFromVegaSpec(spec)

Renders a Vega (not Vega-lite) chart from a JSON / Object specification.

Unlike vega.embedFromVegaSpec() - this renders directly within Jupyter.

Similar to vega.svgFromSpec(), the specification can either be an object or JSON encoded string.

This example is from the Vega Line Chart example

utils.vega.svgFromSpec({
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "A basic line chart example.",
  "width": 500,
  "height": 200,
  "padding": 5,

  "signals": [
    {
      "name": "interpolate",
      "value": "linear",
      "bind": {
        "input": "select",
        "options": [
          "basis",
          "cardinal",
          "catmull-rom",
          "linear",
          "monotone",
          "natural",
          "step",
          "step-after",
          "step-before"
        ]
      }
    }
  ],

  "data": [
    {
      "name": "table",
      "values": [
        {"x": 0, "y": 28, "c":0}, {"x": 0, "y": 20, "c":1},
        {"x": 1, "y": 43, "c":0}, {"x": 1, "y": 35, "c":1},
        {"x": 2, "y": 81, "c":0}, {"x": 2, "y": 10, "c":1},
        {"x": 3, "y": 19, "c":0}, {"x": 3, "y": 15, "c":1},
        {"x": 4, "y": 52, "c":0}, {"x": 4, "y": 48, "c":1},
        {"x": 5, "y": 24, "c":0}, {"x": 5, "y": 28, "c":1},
        {"x": 6, "y": 87, "c":0}, {"x": 6, "y": 66, "c":1},
        {"x": 7, "y": 17, "c":0}, {"x": 7, "y": 27, "c":1},
        {"x": 8, "y": 68, "c":0}, {"x": 8, "y": 16, "c":1},
        {"x": 9, "y": 49, "c":0}, {"x": 9, "y": 25, "c":1}
      ]
    }
  ],

  "scales": [
    {
      "name": "x",
      "type": "point",
      "range": "width",
      "domain": {"data": "table", "field": "x"}
    },
    {
      "name": "y",
      "type": "linear",
      "range": "height",
      "nice": true,
      "zero": true,
      "domain": {"data": "table", "field": "y"}
    },
    {
      "name": "color",
      "type": "ordinal",
      "range": "category",
      "domain": {"data": "table", "field": "c"}
    }
  ],

  "axes": [
    {"orient": "bottom", "scale": "x"},
    {"orient": "left", "scale": "y"}
  ],

  "marks": [
    {
      "type": "group",
      "from": {
        "facet": {
          "name": "series",
          "data": "table",
          "groupby": "c"
        }
      },
      "marks": [
        {
          "type": "line",
          "from": {"data": "series"},
          "encode": {
            "enter": {
              "x": {"scale": "x", "field": "x"},
              "y": {"scale": "y", "field": "y"},
              "stroke": {"scale": "color", "field": "c"},
              "strokeWidth": {"value": 2}
            },
            "update": {
              "interpolate": {"signal": "interpolate"},
              "strokeOpacity": {"value": 1}
            },
            "hover": {
              "strokeOpacity": {"value": 0.5}
            }
          }
        }
      ]
    }
  ]
});

Screenshot of vega svg chart

Parameters:
Name Type Description
spec String | Object

Vega specification

(static) vegaLiteMimeType(vegaLiteSpec)

Sends a vega-lite specification using the vega-lite mime-type.

Note, the vega.svgFromSpec() and vega.embedFromSpec() are recommended, as there are a few situations this has seemed to fail.

See the supported Jupyter Lab mime-types for additional detail

Example
// vega-lite spec examples found here: https://vega.github.io/vega-lite/examples/
utils.vega.vegaLiteMimeType({
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "description": "A simple bar chart with embedded data.",
  "data": {
    "values": [
      {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43},
      {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53},
      {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": {"field": "a", "type": "nominal", "axis": {"labelAngle": 0}},
    "y": {"field": "b", "type": "quantitative"}
  }
});
Parameters:
Name Type Description
vegaLiteSpec Object | String

vega-lite specification

(static) vegaMimeType(vegaSpec)

Send a vega specification using the vega mime-type.

Note, the vega.svgFromVegaSpec() and vega.embedFromVegaSpec() are recommended, as there are some situations this has seemed to fail.

See the supported Jupyter Lab mime-types for additional detail

Example
// vega specification examples found here: https://vega.github.io/vega/examples/
utils.vega.vegaMimeType({
  "$schema": "https://vega.github.io/schema/vega/v5.json",
  "description": "An example of a space-fulling radial layout for hierarchical data.",
  "width": 600,
  "height": 600,
  "padding": 5,
  "autosize": "none",

  "data": [
    {
      "name": "tree",
      "url": "https://vega.github.io/vega/data/flare.json",
      "transform": [
        {
          "type": "stratify",
          "key": "id",
          "parentKey": "parent"
        },
        {
          "type": "partition",
          "field": "size",
          "sort": {"field": "value"},
          "size": [{"signal": "2 * PI"}, {"signal": "width / 2"}],
          "as": ["a0", "r0", "a1", "r1", "depth", "children"]
        }
      ]
    }
  ],
  ...
});
Parameters:
Name Type Description
vegaSpec Object | String

vega specification