• Stars
    star
    115
  • Rank 305,916 (Top 7 %)
  • Language
    R
  • License
    Other
  • Created over 6 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Smooth Polygon Transformations

transformr

R-CMD-check CRAN_Status_Badge CRAN_Download_Badge

If you’ve ever made animated data visualisations you’ll know that arbitrary polygons and lines requires special considerations if the animation is to be smooth and believable. transformr is able to remove all of these worries by expanding tweenr to understand spatial data, and thus lets you focus on defining your animation steps. transformr takes care of matching shapes between states, cutting some in bits if the number doesn’t match between the states, and ensures that each pair of matched shapes contains the same number of anchor points and that these are paired up so as to avoid rotation and inversion during animation.

transformr supports both polygons (with holes), and paths either encoded as simple x/y data.frames or as simpel features using the sf package.

Installation

You can install transformr from CRAN using install.packages('transformr') or grab the development version from github with:

# install.packages("devtools")
devtools::install_github("thomasp85/transformr")

Examples

These are simple, contrieved examples showing how the API works. It scales simply to more complicated shapes.

Polygon

A polygon is simply a data.frame with an x and y column, where each row demarcates an anchor point for the polygon. The polygon is not in closed form, that is, the first point is not repeated in the end. If more polygons are wanted you can provide an additional column that indicate the polygon membership of a column (quite like ggplot2::geom_polygon() expects an x, y, and group variable). If holed polygons are needed, holes should follow the main polygon and be separated with an NA row in the x and y column.

library(transformr)
library(tweenr)
library(ggplot2)
polyplot <- function(data) {
  p <- ggplot(data) + 
    geom_polygon(aes(x, y, group = id, fill = col)) +
    scale_fill_identity() +
    coord_fixed(xlim = c(-1.5, 1.5), ylim = c(-1.5, 1.5))
  plot(p)
}

star <- poly_star()
star$col <- 'steelblue'
circles <- poly_circles()
circles$col <- c('forestgreen', 'firebrick', 'goldenrod')[circles$id]

animation <- tween_polygon(star, circles, 'cubic-in-out', 40, id) %>% 
  keep_state(10)

ani <- lapply(split(animation, animation$.frame), polyplot)

By default the polygons are matched up based on their id. In the above example there’s a lack of polygons in the start-state, so these have to appear somehow. This is governed by the enter function, which by default is NULL meaning new polygons just appear at the end of the animation. We can change this to get a nicer result:

# Make new polygons appear 2 units below their end position
from_below <- function(data) {
  data$y <- data$y - 2
  data
}
animation <- tween_polygon(star, circles, 'cubic-in-out', 40, id, enter = from_below) %>% 
  keep_state(10)

ani <- lapply(split(animation, animation$.frame), polyplot)

Similar to the enter function it is possible to supply an exit function when the start state has more polygons than the end state. These functions get a single polygon with the state it was/will be, that can then be manipulated at will, as long as the same number of rows and columns are returned.

The enter and exit functions have slightly different semantics here than in tweenr::tween_state() where it gets all entering/exiting rows in one go, and not one-by-one

Our last option is to not match the polygons up, but simply say “make everything in the first state, into everything in the last state… somehow”. This involves cutting up polygons in the state with fewest polygons and match polygons by minimizing the distance and area difference between pairs. All of this is controlled by setting match = FALSE in tween_polygon(), and transformr will then do its magic:

animation <- tween_polygon(star, circles, 'cubic-in-out', 40, id, match = FALSE) %>% 
  keep_state(10)

ani <- lapply(split(animation, animation$.frame), polyplot)

Paths

Paths are a lot like polygons, except that they don’t wrap-around. Still, slight differences in how they are tweened exists. Chief among these are that the winding order are not changed to minimize the travel-distance, because paths often have an implicit direction and this should not be tampered with. Further, when automatic matching paths (that is, match = FALSE), paths are matched to minimize the difference in length as well as the pair distance. The same interpretation of the enter, exit, and match arguments remain, which can be seen in the two examples below:

pathplot <- function(data) {
  p <- ggplot(data) + 
    geom_path(aes(x, y, group = id)) +
    coord_fixed(xlim = c(-1.5, 1.5), ylim = c(-1.5, 1.5))
  plot(p)
}
spiral <- path_spiral()
waves <- path_waves()

animation <- tween_path(spiral, waves, 'cubic-in-out', 40, id, enter = from_below) %>% 
  keep_state(10)

ani <- lapply(split(animation, animation$.frame), pathplot)

animation <- tween_path(spiral, waves, 'cubic-in-out', 40, id, match = FALSE) %>% 
  keep_state(10)

ani <- lapply(split(animation, animation$.frame), pathplot)

Simple features

The sf package provides an implemention of simple features which are a way to encode any type of geometry in defined classes and operate on them. transformr supports (multi)point, (multi)linestring, and (multi)polygon geometries which acount for most of the use cases. When using the tween_sf() function any sfc column will be tweened by itself, while the rest will be tweened by tweenr::tween_state(). For any multi type, the tweening progress as if match = FALSE in tween_polygon() and tween_path(), that is polygons/paths are cut and matched to even out the two states. For multipoint the most central points are replicated to ensure the same number of points in each state. One nice thing about sf is that you can encode different geometry types in the same data.frame and plot it all at once:

sfplot <- function(data) {
  p <- ggplot(data) + 
    geom_sf(aes(colour = col, geometry = geometry)) + 
    coord_sf(datum = NA) + # remove graticule
    scale_colour_identity()
  plot(p)
}
star_hole <- poly_star_hole(st = TRUE)
circles <- poly_circles(st = TRUE)
spiral <- path_spiral(st = TRUE)
waves <- path_waves(st = TRUE)
random <- point_random(st = TRUE)
grid <- point_grid(st = TRUE)
df1 <- data.frame(
  geo = sf::st_sfc(star_hole, spiral, random),
  col = c('steelblue', 'forestgreen', 'goldenrod')
)
df2 <- data.frame(
  geo = sf::st_sfc(circles, waves, grid),
  col = c('goldenrod', 'firebrick', 'steelblue')
)

animation <- tween_sf(df1, df2, 'cubic-in-out', 40) %>% 
  keep_state(10)

ani <- lapply(split(animation, animation$.frame), sfplot)

More Repositories

1

patchwork

The Composer of ggplots
R
2,431
star
2

gganimate

A Grammar of Animated Graphics
R
1,935
star
3

ggraph

Grammar of Graph Graphics
R
1,063
star
4

ggforce

Accelerating ggplot2
R
915
star
5

tidygraph

A tidy API for graph manipulation
R
545
star
6

ggplot2_workshop

Material for "Drawing Anything with ggplot2" workshop
491
star
7

lime

Local Interpretable Model-Agnostic Explanations (R port of original Python package)
R
480
star
8

scico

Palettes for R based on the Scientific Colour-Maps
R
409
star
9

tweenr

Interpolate your data
R
399
star
10

fiery

A flexible and lightweight web server
R
242
star
11

shinyFiles

A shiny extension for server side file access
JavaScript
195
star
12

ggfx

Filters and Shaders for 'ggplot2'
R
166
star
13

densityClust

Clustering by fast search and find of density peaks
R
150
star
14

farver

High Performance Colourspace Manipulation in R
R
127
star
15

particles

A particle simulation engine based on a port of d3-force
R
118
star
16

ambient

A Generator of Multidimensional Noise
R
93
star
17

euclid

Exact Computation Geometry Framework Based on 'CGAL'
C++
82
star
18

routr

Routing of Web Requests in R
R
55
star
19

hierarchicalSets

Scalable Set Visualization using Hierarchies
R
54
star
20

Hr

Easy Access to Uppercase H
R
53
star
21

reqres

Powerful classes for http requests and responses
R
36
star
22

curry

Partial Function Application with %<%, %-<%, and %><%
R
30
star
23

FindMyFriends

Fast alignment-free pangenome creation and exploration
R
27
star
24

pipeplotter

Syntactic ggplot2 Sugar for a Tidy World
R
26
star
25

fawkes

An R Interface to the AxiDraw plotter
R
25
star
26

pearls

Operations on Lists of Data Frames
R
18
star
27

PanVizGenerator

Create your own PanViz visualizations
R
18
star
28

ink

The Modern, High-Performant, Graphic Device for R
C++
17
star
29

ggplot2_mechanics

The Mechanics of ggplot2
TeX
16
star
30

plotting_benchmark

Investigating R graphics performance
HTML
16
star
31

grid

personal devel version of grid
R
15
star
32

PanViz

D3 based visualisation for comparative genomics
JavaScript
14
star
33

boundaries

Algorithms for Working With and Modifying Polygon Boundaries
C++
13
star
34

data_imaginist

data_imaginist source
HTML
12
star
35

nanodev

Graphic Devices for R based on NanoVG
C
10
star
36

MSGFgui

A gui overlay and extension for MSGFplus
R
10
star
37

orion

Spatial Searching for Euclid
C++
9
star
38

web_dev_in_R

Web Development for R Users
TeX
9
star
39

heroku-fiery-demo

A demo fiery application for deployment on Heroku
R
8
star
40

unmeshy

A Vector Based 3D Renderer
C++
7
star
41

MSsary

Mass spectrometry data in R
R
7
star
42

RcppSNAP

'Rcpp' Integration for the SNAP Network Library
C++
6
star
43

tidy_graph_analysis

Tidy Network Analysis in R
TeX
6
star
44

polyclid

Polygon Support for Euclid
C++
6
star
45

mzID

An mzIdentML parser for R
R
6
star
46

MSGFplus

An MSGF+ interface for R
R
6
star
47

thomasp85.github.io

The source for data-imaginist.com
HTML
6
star
48

mvpcran

CRAN on a stick
R
5
star
49

shady

Compile and Execute Shaders from R
C++
5
star
50

anomaly

Detecting those outliers
R
4
star
51

firedock

Dockerfiles for fiery
R
4
star
52

phd_dissertation

Pangenome Tools for Rapid, Large-Scale Analysis of Bacterial Genomes
TeX
4
star
53

d3Disco

A showcase for Shiny and D3 integration
JavaScript
4
star
54

pepmaps

R package for quantitative peptidomics
R
2
star
55

masochist

For some reason I’m doing all of this from my phone
R
2
star
56

firedock_test

R
1
star
57

Biotools

Scripts for CMG-Biotools
Perl
1
star
58

firesafety

Security for fiery apps
1
star
59

circosScripts

Perl scripts to automate circos plots
Perl
1
star
60

CHtools

A list of diverse functions for CH
R
1
star