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.
You can use use_vegawidget()
to import and re-export
from vegawidget:
as_vegaspec()
, print()
,
format()
, knit_print()
vw_as_json()
vegawidget()
, vega_embed()
,
vw_set_base_url()
vw_to_svg()
,
vw_to_bitmap()
, vw_write_svg()
,
vw_write_png()
renderVegawidget()
,
vegawidgetOutput()
If you implement an S3 class in your package, you can call
use_vegawidget()
with the name of your class. This will add
more boilerplate code; you will have to provide the code to convert from
your class to a vegaspec
.
If you want to re-export vegawidget’s interactivity functions, you
can then use use_vegawidget_interactive()
to import and
re-export:
vw_add_data_listener()
,
vw_add_signal_listener()
vw_add_event_listener()
vw_handler_data()
,
vw_handler_signal()
, vw_handler_event()
,
vw_handler_add_effect()
vw_shiny_get_data()
,
vw_shiny_get_signal()
,
vw_shiny_get_event()
vw_shiny_set_data()
,
vw_shiny_set_signal()
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 the vegawidget 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()
.
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:
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”.
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 we use for altair.
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 may be an object with an S3 class. In the case
of altair, the name of this S3 class is
"altair.vegalite.v4.api.TopLevelMixin"
.
The first step is generic. In your package-project, your R working
directory is the package’s root directory. When you run
use_vegawidget()
, you can provide the name of the S3 class.
In the case of altair, we run:
vegawidget::use_vegawidget("altair.vegalite.v4.api.TopLevelMixin")
Like the usethis::use_pipe()
example, this call does two
things:
R
directory,
utils-vegawidget.R
and
utils-vegawidget-altair.vegalite.v4.api.TopLevelMixin.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-altair.vegalite.v4.api.TopLevelMixin
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.v4.api.TopLevelMixin()
; the
use_vegawidget()
function has already named it using the
class-name provided.
as_vegaspec.altair.vegalite.v4.api.TopLevelMixin <- function(spec, ...) {
# TODO: if needed, insert code to convert your object to
# something that can be coerced to a vegaspec.
#
# e.g.:
# spec <- spec$to_json()
vegawidget::as_vegaspec(spec, ...)
}
Here, the commented example code is exactly what is needed. The
altair “chart” object,
altair.vegalite.v4.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:
as_vegaspec.altair.vegalite.v4.api.TopLevelMixin <- function(spec, ...) {
spec <- spec$to_json()
vegawidget::as_vegaspec(spec, ...)
}
One last thing, to enable knit-printing of your class, you should
have some code like this in an .onLoad()
function, usually
kept in a file called zzz.R
:
.onLoad <- function(libname, pkgname) {
# you might have other code here, too
vegawidget::s3_register(
"knitr::knit_print",
"altair.vegalite.v4.api.TopLevelMixin"
)
}
The function vegawidget::s3_register()
is copied from
vctrs::s3_register()
; for more details please see its documentation.
At this point, once you document and re-build the package, vegawidget is fully integrated into it.