Introduction to gglite

The gglite package provides a lightweight R interface to the AntV G2 JavaScript visualization library. It follows the Grammar of Graphics framework—the same theoretical foundation behind ggplot2—but renders interactive, web-based charts powered by G2.

A visualization in gglite is built by composing independent layers:

  1. Data – the data frame you want to visualize.
  2. Marks (geometries) – the visual shapes representing data (points, lines, bars, …).
  3. Encodings (aesthetics) – mappings from data columns to visual channels (position, color, size, …).
  4. Scales – control how data values translate to visual values.
  5. Coordinates – the coordinate system (Cartesian, polar, …).
  6. Transforms – statistical or layout transforms applied to the data.
  7. Facets – split data into multiple panels.
  8. Themes – overall visual styling.
  9. Components – axes, legends, titles, tooltips, and labels.

Each layer is added with the pipe operator |>, so building a chart reads naturally from left to right. If you prefer the ggplot2 convention, you can also use + instead of |>—both operators produce identical results. Use whichever you prefer.

1 Data and encodings

Every chart starts with g2(), which accepts a data frame and aesthetic mappings as R formulas:

library(gglite)
g2(mtcars, hp ~ mpg)

You can also set encodings later with encode():

g2(mtcars) |> encode(x = ~ mpg, y = ~ hp, color = ~ cyl)

1.1 Formula interface

You can use R formulas as a shorthand for aesthetic mappings. The left-hand side maps to y and the right-hand side maps to x:

g2(mtcars, hp ~ mpg)

Additional aesthetics like color can be passed alongside the formula:

g2(iris, Sepal.Length ~ Sepal.Width, color = ~ Species)

Use | for faceting:

g2(iris, Sepal.Length ~ Sepal.Width | Species)

A one-sided formula maps only x (useful for histograms or counts):

g2(mtcars, ~ mpg)

Use + on the right-hand side for multiple position fields (parallel coordinates):

g2(iris, ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width,
  color = ~ Species)

1.2 Character string interface

All aesthetic channels also accept plain character strings instead of formulas. This alternative syntax is equivalent—color = 'species' produces the same result as color = ~ species:

g2(mtcars, x = 'mpg', y = 'hp', color = 'cyl')

The encode() function also accepts character strings:

g2(mtcars) |> encode(x = 'mpg', y = 'hp', color = 'cyl')

2 Marks (geometries)

Marks are the visual building blocks. gglite provides 35+ mark types. Here are the most common ones.

2.1 Points (scatter plot)

g2(iris, Sepal.Length ~ Sepal.Width, color = ~ Species) |>
  mark_point()

2.2 Lines

df = data.frame(
  x = rep(1:5, 2), y = c(3, 1, 4, 1, 5, 2, 7, 1, 8, 3),
  group = rep(c('A', 'B'), each = 5)
)
g2(df, y ~ x, color = ~ group) |> mark_line()

2.3 Bars (intervals)

df = data.frame(x = c('A', 'B', 'C', 'D'), y = c(3, 7, 2, 5))
g2(df, y ~ x) |> mark_interval()

2.4 Areas

df = data.frame(x = 1:10, y = c(3, 1, 4, 1, 5, 9, 2, 6, 5, 3))
g2(df, y ~ x) |> mark_area()

2.5 Box plots

g2(iris, Sepal.Width ~ Species) |> mark_boxplot()

2.6 Combining marks

Multiple marks can be layered on the same chart:

df = data.frame(x = c('A', 'B', 'C'), y = c(3, 7, 2))
g2(df, y ~ x) |>
  mark_interval() |>
  mark_text(encode = list(text = 'y'))

3 Automatic marks

When no mark_*() is added to the pipeline, gglite automatically chooses a mark based on the types of the x and y variables:

x type y type Mark Chart type
numeric numeric point Scatter plot
categorical (unique) numeric interval Bar plot
categorical (repeated) numeric beeswarm Beeswarm plot
categorical (repeated, n ≥ 30) numeric beeswarm + density Beeswarm + density
numeric categorical (unique) interval (transposed) Horizontal bar plot
numeric categorical (repeated) beeswarm (transposed) Horizontal beeswarm
numeric categorical (repeated, n ≥ 30) beeswarm + density (transposed) Horizontal beeswarm + density
categorical categorical cell + group Contingency table
Date numeric line Line chart
ts/mts (auto) line Time series line chart
numeric (none) interval + binX Histogram
categorical (none) interval + groupX Count bar chart
(position) (none) line + parallel Parallel coordinates

When x (or y) is categorical, the choice depends on whether the categories are unique in the data. If every category appears exactly once, a bar plot (interval) is drawn. If categories are repeated, a beeswarm plot shows individual data points. When all groups have at least 30 observations, a density curve is overlaid on the beeswarm for a summary view.

This means you can often skip the mark entirely:

3.1 Scatter plot (numeric × numeric)

g2(penguins, bill_len ~ bill_dep, color = ~ species)

3.2 Bar plot (categorical × numeric, unique categories)

When each category appears once, a bar chart is drawn:

df = data.frame(x = c('A', 'B', 'C', 'D'), y = c(3, 7, 2, 5))
g2(df, y ~ x)

3.3 Beeswarm plot (categorical × numeric, repeated categories)

When categories are repeated, individual points are shown in a beeswarm layout:

g2(chickwts, weight ~ feed)

3.4 Beeswarm + density (categorical × numeric, large groups)

When every group has at least 30 observations, a density curve is overlaid on the beeswarm:

g2(penguins, bill_len ~ species)

3.5 Horizontal beeswarm (numeric × categorical)

g2(penguins, species ~ bill_len)

3.6 Contingency table (categorical × categorical)

Cells are automatically colored by the count of each combination:

g2(penguins, island ~ species)

3.7 Line chart (Date × numeric)

df = data.frame(date = Sys.Date() + 0:9, value = cumsum(rnorm(10)))
g2(df, value ~ date)

3.8 Histogram (numeric only)

g2(penguins, ~ bill_len)

3.9 Count bar chart (categorical only)

g2(penguins, ~ species)

3.10 Parallel coordinates (multiple position fields)

g2(penguins, ~ bill_len + bill_dep + flipper_len + body_mass, color = ~ species)

You can still add scales, themes, titles, and other components as usual:

g2(mtcars, hp ~ mpg, color = ~ cyl) |>
  scale_color(type = 'ordinal') |>
  titles('Motor Trend Cars')

If you add any mark_*(), automatic detection is skipped entirely, so explicit marks always take priority.

3.11 Time series

g2() also accepts R time series (ts and mts) objects directly. Univariate series are converted to a data frame with time and value columns; multivariate series are reshaped to long format with time, series, and value columns. The auto-mark feature draws a line chart automatically:

g2(sunspot.year) |> titles('Yearly Sunspot Numbers (1700--1988)')

Multivariate time series produce one line per series:

g2(EuStockMarkets) |> titles('EU Stock Markets (1991--1998)')

4 Scales

Scales control how data values map to visual properties. Use helpers like scale_x(), scale_y(), and scale_color() to configure scales:

g2(mtcars, hp ~ mpg, color = ~ wt) |>
  scale_y(type = 'log') |>
  scale_color(palette = 'viridis')

Custom domain and range:

g2(mtcars, hp ~ mpg) |>
  scale_x(domain = c(10, 35)) |>
  scale_y(domain = c(0, 400))

5 Coordinates

Coordinate systems change how positional encodings are interpreted. gglite supports Cartesian (default), polar, theta, and radial coordinates.

5.1 Polar coordinates (rose chart)

df = data.frame(x = c('A', 'B', 'C', 'D'), y = c(3, 7, 2, 5))
g2(df, y ~ x, color = ~ x) |>
  mark_interval() |>
  coord_polar()

5.2 Theta coordinates (pie chart)

g2(df, y ~ x, color = ~ x) |>
  mark_interval() |>
  transform('stackY') |>
  coord_theta(innerRadius = 0.5)

5.3 Transposing axes

coord_transpose() swaps x and y (similar to ggplot2’s coord_flip()):

g2(df, y ~ x) |>
  mark_interval() |>
  coord_transpose()

6 Transforms

Transforms modify the data before rendering. Use transform() to apply statistical or layout transforms. When using +, the first argument must be unnamed; see ?transform.g2 for details.

6.1 Stacked bars

df = data.frame(
  x = rep(c('A', 'B', 'C'), each = 2), y = c(3, 2, 5, 4, 1, 6),
  color = rep(c('a', 'b'), 3)
)
g2(df, y ~ x, color = ~ color) |>
  mark_interval() |>
  transform('stackY')

6.2 Dodged bars

g2(df, y ~ x, color = ~ color) |>
  mark_interval() |>
  transform('dodgeX')

6.3 Stacked area chart

df = data.frame(
  x = rep(1:5, 2), y = c(3, 1, 4, 1, 5, 2, 7, 1, 8, 3),
  group = rep(c('A', 'B'), each = 5)
)
g2(df, y ~ x, color = ~ group) |>
  mark_area() |>
  transform('stackY')

7 Facets

Faceting splits data into panels. Use facet_rect() for a grid layout:

g2(iris, Sepal.Length ~ Sepal.Width, color = ~ Species) |>
  facet_rect(~ Species)

The formula interface supports faceting with |. Use | var for column facets, | 0 + var for row facets, and | var1 + var2 for both:

# Column facet: panels arranged in columns by species
g2(penguins, bill_len ~ bill_dep | species)
# Row facet: panels arranged in rows by island
g2(penguins, bill_len ~ bill_dep | 0 + island)
# Both: columns by species, rows by island
g2(penguins, bill_len ~ bill_dep | species + island)

8 Themes

Themes change the overall look. Built-in themes include theme_classic() (default), theme_classic_dark(), theme_light(), theme_dark(), and theme_academy():

g2(iris, Sepal.Length ~ Sepal.Width, color = ~ Species) |>
  theme_academy()

9 Components

Components are the non-data elements of a chart: titles, tooltips, axes, legends, and labels.

9.1 Titles

g2(mtcars, hp ~ mpg) |>
  titles('Motor Trend Cars', subtitle = 'mpg vs horsepower')

9.2 Tooltips

g2(sunspot.year) |> tooltip(crosshairs = TRUE)

9.3 Labels

Use labels() to add text annotations. When using +, the first argument must be unnamed; see ?labels.g2 for details.

df = data.frame(x = c('A', 'B', 'C', 'D'), y = c(3, 7, 2, 5))
g2(df, y ~ x) |>
  mark_interval() |>
  labels(text = ~ y)

10 Interactions

Interactions add user-driven behaviors like hovering, brushing, and filtering:

g2(iris, Sepal.Length ~ Sepal.Width, color = ~ Species) |>
  interact('tooltip') |>
  interact('legendFilter') |>
  interact('brushHighlight')

11 Putting it all together

Here is a more complete example combining several grammar layers:

df = data.frame(
  x = rep(c('Q1', 'Q2', 'Q3', 'Q4'), each = 2),
  y = c(120, 80, 150, 90, 180, 110, 200, 130),
  product = rep(c('Widget', 'Gadget'), 4)
)
g2(df, y ~ x, color = ~ product) |>
  mark_interval() |>
  transform('dodgeX') |>
  scale_color(range = c('#5470c6', '#91cc75')) |>
  titles('Quarterly Sales', subtitle = 'By product line') |>
  interact('tooltip') |>
  interact('elementHighlightByX') |>
  theme_classic()

12 Using + instead of |>

If you are used to ggplot2, you can replace |> with +. Both operators produce identical charts:

# Pipe style
g2(iris, Sepal.Length ~ Sepal.Width, color = ~ Species) |>
  scale_color(palette = 'set2') |>
  titles('Iris Dataset')
# ggplot2 style
g2(iris, Sepal.Length ~ Sepal.Width, color = ~ Species) +
  scale_color(palette = 'set2') +
  titles('Iris Dataset')

You can mix modifiers freely—marks, scales, coordinates, themes, facets, transforms, and components all work with +:

df = data.frame(x = c('A', 'B', 'C', 'D'), y = c(3, 7, 2, 5))
g2(df, y ~ x, color = ~ x) +
  mark_interval() +
  coord_polar() +
  titles('Polar Bar Chart') +
  theme_academy()

You can even freely mix + and |> in the same expression—due to R’s operator precedence (|> binds tighter than +), any combination produces the same result:

# These are all equivalent:
g2(mtcars, hp ~ mpg) |>
  scale_x(type = 'log') + theme_dark()
g2(mtcars, hp ~ mpg) +
  scale_x(type = 'log') + theme_dark()