Code Monkey home page Code Monkey logo

virgo's Introduction

CRAN status lifecycle R-CMD-check

vegawidget

Vega-Lite is an implementation of the grammar-of-graphics, rendered in the browser with interactivity.

The goal of vegawidget is to render Vega-Lite and Vega specifications as htmlwidgets, and to help you communicate with a Vega chart using JavaScript or Shiny. Its ambition is to be a low-level interface to the Vega(-Lite) API, so that other packages can build upon it.

Accordingly, this package may be useful to:

  • build (using lists of lists) re-usable Vega and Vega-Lite specifications for deployment elsewhere.
  • develop higher-level, user-friendly packages to compose specific types of plots, or even to build a general ggplot2-like framework, using this package as the rendering foundation.

Features

New to vegawidget 0.4

  • vegawidget now supports the last two Vega-Lite major-versions, currently versions 5 and 4.

    However, for a given R session (e.g. rendering of an RMarkdown file), the vegawidget() function can use only one major-version; this version is determined using the $schema element of the first vegaspec evaluated using vegawidget().

    This restriction does not apply to the image functions, e.g. vw_to_svg(), or to the compilation function, vw_to_vega().

  • use vega_version_all() to see the available versions:

library("vegawidget")

vega_version_all()
#>   widget vega_lite   vega vega_embed
#> 1    vl5    5.16.3 5.24.0     6.22.2
#> 2    vl4    4.17.0 5.17.0     6.12.2
  • Compiling a spec and creating an image now uses the V8 package, rather than depending on a local installation of nodejs.

Installation

You can install vegawidget from CRAN with:

install.packages("vegawidget")

The development version of vegawidget is available from GitHub with:

# install.packages("devtools")
devtools::install_github("vegawidget/vegawidget")

Note: There are documentation websites for both the CRAN version and the development version of this package.

Introduction

Vega(-Lite) specifications are just text, formatted as JSON. However, in R, we can use lists to build specifications:

library("vegawidget")

spec_mtcars <-
  list(
    `$schema` = vega_schema(), # specifies Vega-Lite
    description = "An mtcars example.",
    data = list(values = mtcars),
    mark = "point",
    encoding = list(
      x = list(field = "wt", type = "quantitative"),
      y = list(field = "mpg", type = "quantitative"),
      color = list(field = "cyl", type = "nominal")
    )
  ) %>% 
  as_vegaspec()

The as_vegaspec() function is used to turn the list into a vegaspec; many of this package’s functions are built to support, and render, vegaspecs:

spec_mtcars

The rendering of the chart above depends on where you are reading it:

  • On this package’s pkgdown site, it is rendered as part of an HTML environment, showing its full capabilities.

  • At its GitHub code site, the chart is further rendered to a static SVG file, then incorporated into the Markdown rendering.

A learnr tutorial is available: learnr::run_tutorial("overview", package = "vegawidget").

For more, please see our Getting Started article. Additionally, the Vega-Lite website has a comprehensive introduction.

Other articles for this package:

Acknowledgements

  • Alicia Schep has been instrumental in guiding the evolution of the API, and for introducing new features, particularly the JavaScript and Shiny functions.
  • Haley Jeppson and Stuart Lee have provided valuable feedback and contributions throughout the package’s development.
  • Bob Rudis and the vegalite package provided a lot of the inspiration for this work, providing a high-level interface to Vega-Lite.
  • The Altair developers, for further popularizing the notion of using a programming language (Python) to create and render Vega-Lite specifications.
  • The Vega-Lite developers, for providing a foundation upon which the rest of this is built.

Contributing

Contributions are welcome, please see this guide. Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

virgo's People

Contributors

earowang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

virgo's Issues

gadget mode

so I think it would be useful to return the event coordinates (i.e. bounding box of a brush or click event) to the R session, especially for EDA. The only way I think we could do this currently is via shiny. One thought I had would be to have an option that sets viewer to use shiny as a backend with runGadget(). This would still run the plot in the rstudio viewer but would allow our plot object to track events.

linking is not working for multiple data sources with shared id

Here is a minimal example where df1 and df2 share the same volume id.

When concatenating scatter_plot and ts_plot using the second chunk of code, making a selection on scatter_plot doesn't show the relevant series in the ts_plot.

I'm aware that changing the dataset of ts_plot to df2 %>% left_join(df1, by = "id") will work, but the common id column should be sufficient for the two plots to be linked.

library(tibble)
library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#> 
#>     date, intersect, setdiff, union

set.seed(123)
df1 <- tibble(
  id = 1:10,
  x = runif(10),
  y = runif(10)
)

df2 <- tidyr::expand_grid(
  id = 1:10,
  date = seq(ymd("2020/01/01"), ymd("2020/01/31"), by = "day")
) %>% 
  add_column(value = runif(nrow(.)))

df1
#> # A tibble: 10 x 3
#>       id      x      y
#>    <int>  <dbl>  <dbl>
#>  1     1 0.288  0.957 
#>  2     2 0.788  0.453 
#>  3     3 0.409  0.678 
#>  4     4 0.883  0.573 
#>  5     5 0.940  0.103 
#>  6     6 0.0456 0.900 
#>  7     7 0.528  0.246 
#>  8     8 0.892  0.0421
#>  9     9 0.551  0.328 
#> 10    10 0.457  0.955
df2
#> # A tibble: 310 x 3
#>       id date       value
#>    <int> <date>     <dbl>
#>  1     1 2020-01-01 0.890
#>  2     1 2020-01-02 0.693
#>  3     1 2020-01-03 0.641
#>  4     1 2020-01-04 0.994
#>  5     1 2020-01-05 0.656
#>  6     1 2020-01-06 0.709
#>  7     1 2020-01-07 0.544
#>  8     1 2020-01-08 0.594
#>  9     1 2020-01-09 0.289
#> 10     1 2020-01-10 0.147
#> # … with 300 more rows

Created on 2021-04-30 by the reprex package (v2.0.0)

library(virgo)
selection <- select_interval()

scatter_plot <- df1 %>% 
  vega() %>% 
  mark_point(enc(x = x, y = y),
             selection = selection)

ts_plot <- df2 %>% 
  vega() %>% 
  mark_line(enc(x = date, y = value, group = id),
            selection = selection)

hconcat(scatter_plot, ts_plot)

Need magrittr in imports?

I tried running the first example and got the following.

could not find function "%>%"

You need to usethis::use_pipe()?

PS: great pkg! How very exciting!

Missing values

Shall we handle missing values as is now? or different?

library(dplyr)
movies <- jsonlite::read_json(
  "https://vega.github.io/vega-editor/app/data/movies.json"
  , simplifyVector = TRUE)
movies <- movies %>%
  mutate(missing = is.na(IMDB_Rating) | is.na(Rotten_Tomatoes_Rating))
movies %>%
  vega(enc(IMDB_Rating, Rotten_Tomatoes_Rating, colour = missing)) %>%
  mark_point() %>%
  config(mark = list(invalid = NULL))

input

  • vega inputs: input_*()
  • shiny reactive inputs

Dot in the function

I think missing values / logical values aren't being properly handled. i.e.

penguins %>%
  vega() %>%
  mark_point(enc(x = bill_length_mm, y = bill_depth_mm, color = is.na(sex)))

Produces a legend where all points are undefined.

Reactive data for virgo

@ijlyttle has a bunch of event/signal/data listeners in vegawidget for use with shiny, should we re-export / alias them in virgo?

Should the data argument in virgo functions accept a shiny reactive()?

And would this be possible without shiny at all? One thought would be using sketch but not sure how mature that is.

scale seems to be broken

cars <-
  jsonlite::fromJSON("https://vega.github.io/vega-editor/app/data/cars.json")

cars %>% 
  vega() %>% 
  mark_bar(
    enc(
      x = vg_count(), 
      y = Name, 
    )
  ) %>% 
  scale_y(breaks = NULL)

Error occurs at rescale_domain()

should we write a design doc?

@ijlyttle @earowang - do you think it would be worthwhile making our design explicitly stated? I think what we've got so far is really exciting but I do think it would be worth clarifying the API spec, especially around the problems with interactivity?

debug mode

For debugging it's often useful to go to vg editor. Similar to #12 I think it would be useful to allow the user to open a virgo obj in the vega editor, manipulate it and then return the updated version to the R session. How to actually implement this is another question lol

selections API

As discussed, we don't want to over complicate the NSE data mask by incorporating selections directly. Here's a few ways that a selection can interact with the vega-lite spec:

  1. transformations of the data (using "transform" field). Most commonly used to filter data based on the selection.

  2. modifying the encoding spec via either "condition" or the "scale" fields.

For 2. I think we proposed using a verb based approach, that acts like an ifelse or case_when type function

selection <- select_interval(encoding = "x")
mtcars %>%
  vega() %>%
  mark_point(
    encoding = enc(x = wt, y = mpg, color = factor(cyl)),
    selection = selection) %>%
  where(selection, encoding = "opacity", 0.1, 1)

The where verb acts on the selection and the encoding to produce a true / false condition. In this case the where updates opacity channel so points are transparent on the x brush. Specifiying TRUE instead of a value would make it explicit that you are using the encoding already present. Like making points grey;

selection <- select_interval(encoding = "x")
mtcars %>%
  vega() %>%
  mark_point(
    encoding = enc(x = wt, y = mpg, color = factor(cyl)),
    selection = selection) %>%
  where(selection, encoding = "color", TRUE, "grey")

An alternate here would be to split these conditions into two functions, to represent conditional encodings:

selection <- select_interval(encoding = "x")
mtcars %>%
  vega() %>%
  mark_point(
    encoding = enc(x = wt, y = mpg, color = factor(cyl)),
    selection = selection) %>%
  encode_if(selection, encoding = "color", TRUE, "grey")

Or binding to a scale with scale_if()

There are probably other ways too!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.