The vegawidget package is designed to be a low-level interface to the Vega and Vega-Lite visualization frameworks. As such, we hope that the functions provided here can serve as a foundation for other, presumably higher-level, packages. To make it easier for authors of such packages, we offer a function use_vegawidget() to help incorporate vegawidget functions into those packages.

Example: altair

For example, the altair package provides an R interface to the Altair Python package. The altair package itself provides the connection to Python, using reticulate; altair’s focus is to provide a means to build a Vega-Lite specification - using higher-level abstractions than lists.

The rendering part of altair is handled by this package. A number of vegawidget functions are imported into altair, then re-exported. From altair’s perspective, this import-export operation is handled by a single vegawidget function: use_vegawidget().

Inspiration: usethis::use_pipe()

A lot of packages use the pipe (%>%) function, so much so that the usethis package offers the function usethis::use_pipe() for package authors to make the pipe part of their package’s offer:

  • adds the magrittr package to the “Imports” section of the package’s DESCRIPTION file
  • creates a new file in the package’s R directory, utils-pipe.R

This new file contains roxygen directives that will handle the importing and exporting the next time you build the package’s documentation. Now, people who install this package will have access to the pipe operator without having to refer explicitly to the magrittr package. It “just works”.

Implementation: altair

We wish to bring a similar robustness and ease-of-use to package authors who want to incorporate vegawidget. To demonstrate how to do this, we will show the process that is already in place with the altair package.

The use_vegawidget() function makes a couple of related assumptions about your package. It assumes that your package builds Vega and Vega-Lite specifications, and that the object that you use to contain a specification object is an S3 object. In the case of altair, the name of this S3 class is "altair.vegalite.v2.api.TopLevelMixin".

The first step is generic. With your package-project open, with your R working directory being the package’s root directory. When you run use_vegawidget(), you will have to provide to provide the name of the S3 class. In the case of altair, we would run:

vegawidget::use_vegawidget("altair.vegalite.v2.api.TopLevelMixin")

Like the usethis::use_pipe() example, this call does two things:

  • adds the vegawidget package to the “Imports” section of the package’s DESCRIPTION file
  • creates a new file in the package’s R directory, utils-vegawidget.R

However, you have a little bit more work to do before you’re done. You need to edit your new copy of utils-vegawidget.R to tell it how to convert your S3 class to a vegaspec. The part of the file that you need to edit is at the very top.

In the case of altair, the name of the function is as_vegaspec.altair.vegalite.v2.api.TopLevelMixin(); the use_vegawidget() function has already named it using the class-name provided.

Here, the commented example code is exactly what is needed. The altair “chart” object, altair.vegalite.v2.api.TopLevelMixin, has a method, to_json() to write out the specification to JSON. The vegawidget as_vegaspec() generic has a method for JSON-formatted strings (it also has a method for lists). So our “finished” product looks like:

At this point, once you document and re-build the package, vegawidget is fully integrated.

One final note, when you open your copy of utils-vegawidget.R, you will notice that a lot of functions are imported and exported. If there are functions that you do not wish to incorporate into your package, you can delete the reference to them in this file, then re-document and rebuild.