Skip to contents

smallvis lets you experiment with neighborhood embedding methods, including t-SNE and the LargeVis and UMAP cost functions. You can change the input scaling, affinities, initialization, and optimizer independently. Most methods use quadratic time and memory and suit small datasets; Barnes-Hut t-SNE provides an approximate route for larger inputs.

Install

The package lives in the smallvis subdirectory of the repository. Install it and its dependencies, including the GitHub plotting package vizier, with:

install.packages("pak")
pak::pak("jlmelville/smallvis/smallvis")

Installation from source requires an R-compatible C++ toolchain, such as Rtools on Windows.

Make an embedding

smallvis() selects the numeric columns of a data frame, so the species column in iris stays out of the calculation. Here t-SNE starts from scaled PCA coordinates and returns a two-column matrix. Plotting during optimization is disabled so that the example also works in scripts.

library(smallvis)

embedding <- smallvis(
  iris,
  Y_init = "spca",
  perplexity = 30,
  epoch_callback = FALSE,
  n_threads = 1,
  verbose = FALSE
)
dim(embedding)
## [1] 150   2
species <- as.integer(iris$Species)
plot(
  embedding,
  col = c("#0072B2", "#D55E00", "#009E73")[species],
  pch = species,
  xlab = "t-SNE 1",
  ylab = "t-SNE 2"
)

Two-dimensional t-SNE embedding of iris, with species distinguished by color and plotting symbol.

The coordinates describe a neighborhood embedding: nearby points are the relationships the method tries to preserve. The perplexity experiments show how changing the neighborhood size changes the picture.

Inspect the result

Set ret_extra = TRUE to return a list containing the coordinates in Y, final objective contributions in costs, and an optimization history in itercosts.

fit <- smallvis(
  iris,
  Y_init = "spca",
  perplexity = 30,
  ret_extra = TRUE,
  epoch_callback = FALSE,
  n_threads = 1,
  verbose = FALSE
)
c(iterations = fit$iter, final_cost = sum(fit$costs))
##   iterations   final_cost 
## 1000.0000000    0.1231099

The final cost is evaluated at the returned coordinates after removing exaggeration. Values in the history were recorded during optimization and can include exaggeration. The function reference describes the available diagnostics, including optional matrices that can be expensive to calculate or retain.

Plot during optimization

The default epoch_callback = TRUE uses vizier to plot progress. You can also supply your own callback. This example colors points by species and puts the iteration number in the title:

iris_plot <- function(Y, iter, cost = NULL) {
  plot(Y, col = as.integer(iris$Species), main = paste("Iteration", iter))
}
smallvis(iris, Y_init = "spca", epoch_callback = iris_plot)

Where next?