Earlier this week Mike Bostock tweeted a interesting looking contour plot with a link to edit the formula and manipulate the graphic using D3.js.

I decided I would attempt to recreate the image using **ggplot2**, and animate it using the new **gganimate** package.

## Creating the data

I started by creating a data frame with all the combinations of `x`

and `y`

on a grid between -10 and 10, in intervals of 0.1. Then I defined a third variable, `z`

as a function of `x`

and `y`

, using the same equation as originally used here.

```
<- crossing(x = seq(-10, 10, 0.1), y = seq(-10, 10, 0.1)) %>%
plot_data mutate(z = sin(sin(x * (sin(y) - cos(x)))) - cos(cos(y * (cos(x) - sin(y)))))
plot_data#> # A tibble: 40,401 × 3
#> x y z
#> <dbl> <dbl> <dbl>
#> 1 -10 -10 -1.77
#> 2 -10 -9.9 -0.950
#> 3 -10 -9.8 -0.275
#> 4 -10 -9.7 -0.138
#> 5 -10 -9.6 0.0279
#> 6 -10 -9.5 -1.01
#> 7 -10 -9.4 -1.80
#> 8 -10 -9.3 -1.28
#> 9 -10 -9.2 -0.564
#> 10 -10 -9.1 -0.227
#> # … with 40,391 more rows
```

Now we can use that data to make the image!

## Create the plot

To create the plot, we are basically making a heat map of sorts, where the fill is defined by the newly calculated `z`

variable. I use `geom_raster`

because it offers speed improvements over `geom_tile`

when all tiles are the szme size, which they are in this case. Given that we have a lot of tiles, I’ll take the speed!

```
ggplot(plot_data, aes(x = x, y = y)) +
geom_raster(aes(fill = z), interpolate = TRUE, show.legend = FALSE) +
scale_fill_viridis_c(option = "C") +
coord_equal() +
theme_void()
```

Pretty good! But then, Jeff Baumes upped the stakes!

Well now I can’t not animate it. So…

## Add time and animate

To create an animated plot, we need a time variable, `t`

. We start by creating a data frame similar to the one we created above. It includes all combinations of `x`

and `y`

from -10 to 10 in increments of 0.1, but now those values are also cross with the time variable, `t`

, which goes from 0 to 5 in increments of 0.1. The `z`

variable, which will still be our fill color, is now a function of `x`

, `y`

, and `t`

, as in Jeff’s example. Finally, we can use the same **ggplot2** code as above, with the addition of the `transition_time`

function from **gganimate**.

```
= data_frame(t = c(seq(0, 5, 0.1), seq(4.9, 0, -0.1)),
t_lookup t2 = seq(0, 10, 0.1))
<- crossing(x = seq(-10, 10, 0.1), y = seq(-10, 10, 0.1),
plot_data t2 = seq(0, 10, 0.1)) %>%
left_join(t_lookup, by = "t2") %>%
mutate(z = sin(sin(x * (sin(y + t) - cos(x - t)))) - cos(cos(y * (cos(x - t) - sin(y + t)))))
ggplot(plot_data, aes(x = x, y = y)) +
geom_raster(aes(fill = z), interpolate = TRUE, show.legend = FALSE) +
scale_fill_viridis_c(option = "C") +
coord_equal() +
theme_void() +
transition_time(t2)
```

And there we have it! With just one extra variable and one additional line of code for our plot, we have an animated contour plot!

## Acknowledgments

Featured photo by Dan Meyers on Unsplash.