transformr/ 0000755 0001762 0000144 00000000000 14567120152 012452 5 ustar ligges users transformr/NAMESPACE 0000644 0001762 0000144 00000002647 14567110436 013706 0 ustar ligges users # Generated by roxygen2: do not edit by hand
export(path_spiral)
export(path_waves)
export(point_grid)
export(point_random)
export(poly_circle)
export(poly_circles)
export(poly_star)
export(poly_star_hole)
export(st_normalize)
export(tween_path)
export(tween_polygon)
export(tween_sf)
import(vctrs)
importFrom(lpSolve,lp.assign)
importFrom(rlang,"%||%")
importFrom(rlang,as_function)
importFrom(rlang,enquo)
importFrom(rlang,eval_tidy)
importFrom(rlang,quo)
importFrom(rlang,quo_is_null)
importFrom(sf,"st_crs<-")
importFrom(sf,"st_geometry<-")
importFrom(sf,st_area)
importFrom(sf,st_as_sfc)
importFrom(sf,st_bbox)
importFrom(sf,st_cast)
importFrom(sf,st_centroid)
importFrom(sf,st_combine)
importFrom(sf,st_crs)
importFrom(sf,st_distance)
importFrom(sf,st_geometry)
importFrom(sf,st_geometry_type)
importFrom(sf,st_intersection)
importFrom(sf,st_length)
importFrom(sf,st_linestring)
importFrom(sf,st_multilinestring)
importFrom(sf,st_multipoint)
importFrom(sf,st_multipolygon)
importFrom(sf,st_point)
importFrom(sf,st_polygon)
importFrom(sf,st_sample)
importFrom(sf,st_sfc)
importFrom(sf,st_touches)
importFrom(sf,st_transform)
importFrom(sf,st_union)
importFrom(sf,st_voronoi)
importFrom(stats,runif)
importFrom(tweenr,.complete_states)
importFrom(tweenr,.get_last_frame)
importFrom(tweenr,.has_frames)
importFrom(tweenr,.max_id)
importFrom(tweenr,.with_prior_frames)
importFrom(tweenr,tween_state)
useDynLib(transformr, .registration = TRUE)
transformr/LICENSE.note 0000644 0001762 0000144 00000001711 13261754001 014417 0 ustar ligges users This package contains the C++ library earcut developed by Mapbox
and released under the ISC license. The full license for this is reproduced
below.
________________________________________________________________________________
ISC License
Copyright (c) 2015, Mapbox
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
transformr/LICENSE 0000644 0001762 0000144 00000000061 13245061637 013460 0 ustar ligges users YEAR: 2018
COPYRIGHT HOLDER: Thomas Lin Pedersen
transformr/README.md 0000644 0001762 0000144 00000017007 14277147064 013747 0 ustar ligges users
# transformr
[](https://github.com/thomasp85/transformr/actions/workflows/R-CMD-check.yaml)
[](https://cran.r-project.org/package=transformr)
[](https://cran.r-project.org/package=transformr)
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`](https://github.com/thomasp85/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`](https://github.com/r-spatial/sf) package.
## Installation
You can install transformr from CRAN using
`install.packages('transformr')` or grab the development version from
github with:
``` r
# 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.
``` r
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:
``` r
# 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:
``` r
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:
``` r
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)
```

``` r
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:
``` r
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)
```

transformr/man/ 0000755 0001762 0000144 00000000000 14534600134 013222 5 ustar ligges users transformr/man/tween_path.Rd 0000644 0001762 0000144 00000006312 14277146520 015661 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tween_path.R
\name{tween_path}
\alias{tween_path}
\title{Transition between path data frames}
\usage{
tween_path(
.data,
to,
ease,
nframes,
id = NULL,
enter = NULL,
exit = NULL,
match = TRUE
)
}
\arguments{
\item{.data}{A data.frame to start from. If \code{.data} is the result of a prior
tween, only the last frame will be used for the tween. The new tween will
then be added to the prior tween}
\item{to}{A data.frame to end at. It must contain the same columns as .data
(exluding \code{.frame})}
\item{ease}{The easing function to use. Either a single string or one for
each column in the data set.}
\item{nframes}{The number of frames to calculate for the tween}
\item{id}{The column to match observations on. If \code{NULL} observations will be
matched by position. See the \emph{Match, Enter, and Exit} section for more
information.}
\item{enter, exit}{functions that calculate a start state for new observations
that appear in \code{to} or an end state for observations that are not present in
\code{to}. If \code{NULL} the new/old observations will not be part of the tween. The
function gets a data.frame with either the start state of the exiting
observations, or the end state of the entering observations and must return
a modified version of that data.frame. See the \emph{Match, Enter, and Exit}
section for more information.}
\item{match}{Should polygons be matched by id? If \code{FALSE} then polygons will
be matched by shortest distance and if any state has more polygons than the
other, the other states polygons will be chopped up so the numbers match.}
}
\value{
A data.frame containing intermediary states
}
\description{
This function is equivalent to \code{\link[tweenr:tween_state]{tweenr::tween_state()}} but expects the data
to have an \code{x} and \code{y} column and encode paths.
}
\section{Aligning paths}{
There is less work required to align paths than there is to align polygons,
simply because no rotation is possible/required, and the notion of clockwise
winding order is not meaningful in the scope of paths. Still, paths need to
be matched and the number of points in each pair of matched paths must be
equal. Paths are matched based on relative length rather than on position and
seek to minimize the change in length during transition. This is chosen from
the point of view that huge elongation or contraction are much more
distracting than longer travel distances.
}
\section{Cutting paths}{
If the number of paths to transition between is not even, some of the paths
need to be cut in order to succesfully match the paths. The cuts are
distributed based on the same algorithm that distributes cuts in polygons and
seek to cut the lines into as even-length pieces as possible.
}
\section{Multipaths}{
It is possible to encode multiple paths with the same id be separating them
with a \code{NA} row, much in the same way as holes are encoded in polygons. If
paths are not matched based on id (\code{match = FALSE}) then multipaths will
simply be split into separate paths. On the other hand, if paths are matched
by id all paths within a multipath will transition into the (multi)path that
has the same id in the other state.
}
transformr/man/simple_shapes.Rd 0000644 0001762 0000144 00000003533 13262673455 016366 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/shapes.R
\name{simple_shapes}
\alias{simple_shapes}
\alias{poly_circle}
\alias{poly_circles}
\alias{poly_star}
\alias{poly_star_hole}
\alias{path_spiral}
\alias{path_waves}
\alias{point_random}
\alias{point_grid}
\title{Some different geometries to play with}
\usage{
poly_circle(st = FALSE, detail = 360)
poly_circles(st = FALSE, n = 3, r = 0.25, detail = 360)
poly_star(st = FALSE, n = 5, r1 = 0.5)
poly_star_hole(st = FALSE, n = 5, r1 = 0.5)
path_spiral(st = FALSE, windings = 5)
path_waves(st = FALSE, w1 = 7, w2 = 11)
point_random(st = FALSE, n = 10)
point_grid(st = FALSE, dim = 5)
}
\arguments{
\item{st}{Logical. Should the geometry be returned as an \code{sf} feature?}
\item{detail}{The number of points defining the shape}
\item{n}{For \code{poly_circles} the number of circles, for \code{poly_star} and
\code{poly_star_hole} the number of 'arms', and for \code{point_random} the number of
points}
\item{r, r1}{The radius of the geometry. \code{r} gives the radius of the circles
in \code{poly_circles} and \code{r1} gives the inner radius for
\code{poly_star}/\code{poly_star_hole}, thus determining how pointy it is}
\item{windings}{The number of revolutions in the spiral}
\item{w1, w2}{The frequency for the two sine waves}
\item{dim}{the number of rows and columns in the grid}
}
\value{
Either a data.frame or an sf feature depending on the value of \code{st}
}
\description{
These functions are provided to allow you to play with somee simple shapes as
you explore \code{transformr} and are also used in the examples for the different
tween functions. All geometries can be returned as either a standard
\code{data.frame} with \code{x}, \code{y}, and \code{id} column, or as an sf geometry of the
appropriate type.
}
\examples{
# Create a 7-pointed star
poly_star(n = 7)
}
transformr/man/transformr-package.Rd 0000644 0001762 0000144 00000002006 14277146520 017305 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/transformr-package.R
\docType{package}
\name{transformr-package}
\alias{transformr}
\alias{transformr-package}
\title{transformr: Polygon and Path Transformations}
\description{
\if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}}
In order to smoothly animate the transformation of polygons and paths, many aspects needs to be taken into account, such as differing number of control points, changing center of rotation, etc. The 'transformr' package provides an extensive framework for manipulating the shapes of polygons and paths and can be seen as the spatial brother to the 'tweenr' package.
}
\seealso{
Useful links:
\itemize{
\item \url{https://github.com/thomasp85/transformr}
\item Report bugs at \url{https://github.com/thomasp85/transformr/issues}
}
}
\author{
\strong{Maintainer}: Thomas Lin Pedersen \email{thomasp85@gmail.com} (\href{https://orcid.org/0000-0002-5147-4711}{ORCID})
}
\keyword{internal}
transformr/man/st_normalize.Rd 0000644 0001762 0000144 00000001425 13316670035 016225 0 ustar ligges users % Generated by roxygen2: do not edit by hand
% Please edit documentation in R/tween_polygon.R
\name{st_normalize}
\alias{st_normalize}
\title{Normalise a geometry to fit inside a unit square}
\usage{
st_normalize(st)
}
\arguments{
\item{st}{An sf geometry such as \code{sf}, \code{sfc}, or \code{sfg}}
}
\value{
An object of the same type as \code{st}
}
\description{
This is a small helper function that will take an sf geometry and fit it
inside the unit square (a square centered on 0 and ranging from -1 to 1 in
both dimensions). The function will retain the aspect ratio of the geometry
and simply scale it down until it fits.
}
\examples{
library(sf)
nc <- st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
st_bbox(nc)
nc_norm <- st_normalize(nc)
st_bbox(nc_norm)
}
transformr/man/figures/ 0000755 0001762 0000144 00000000000 14567113102 014666 5 ustar ligges users transformr/man/figures/logo.png 0000644 0001762 0000144 00000056716 13401217776 016363 0 ustar ligges users PNG
IHDR y X siCCPicc (u+Q?hbBq461%n-ZZ3eRۼ$UnW낿[Z)"%\7j<=y:9`攼0 BQؼX]qEWu3xZ;Z)]KjEIjQ5y[CƓ§M.(|k
Z4 k+Xjyay9|nE|#U#֍N ~\L1Aa?N@9eUīD,EwK5ͽ
8i8߄5˒M̚N Ơ*=s|u+݃>9\gpC cHRM z&