/
non-standard-aesthetic-rotation.Rmd
124 lines (96 loc) · 3.74 KB
/
non-standard-aesthetic-rotation.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
---
title: "Non-Standard Aesthetic: Rotation"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Non-Standard Aesthetic: Rotation}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
```{r setup}
library(ggplot2)
library(ggsvg)
```
## Introduction
This example steps through the process of creating an SVG and mapping
an SVG characteristic into a ggplot2 aesthetic.
ggplot2 aesthethics are not limited to colour, fill, size etc.
*Anything* in SVG can be used as a target for an aesthetic mapping.
In this example the **rotation** of an SVG arrow is controlled via a value in
a data.frame.
Overview:
1. Introduce parameters with [glue](https://cran.r-project.org/package=glue) syntax,
using double curly braces `{{}}`
2. Set the defaults for these parameters using `geom_point_svg(..., defaults = list(...))`
3. Use these parameters as aesthetics
4. Add an appropriate `scale_svg_*()` to inform ggplot2 how to map values to
this parameter (which it will then insert into the SVG text)
#### Define the base SVG
```{r fig.height=1.5}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Generic SVG arrow
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arrow_text <- '
<svg viewBox="0 0 100 100">
<g transform="rotate(45 50 50)">
<line x1="10" y1="50" x2="90" y2="50" stroke="black" stroke-width="2" />
<line x1="70" y1="30" x2="90" y2="50" stroke="black" stroke-width="2" />
<line x1="70" y1="70" x2="90" y2="50" stroke="black" stroke-width="2" />
</g>
</svg>
'
grid::grid.draw( svg_to_rasterGrob(arrow_text) )
```
#### Create parameterised SVG
In order to create a responsive SVG that has values dynamically mapped
in `ggplot2`, add named parameters in place of values in the SVG text.
In this example the SVG transform to rotate the arrow is `rotate(45 50 50)`
and this has been parameterised to `rotate({{angle}} 50 50 )`.
```{r fig.height=1.5}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# SVG arrow with controllable rotation angle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arrow_text <- '
<svg viewBox="0 0 100 100">
<g transform="rotate({{arrow_angle}} 50 50)">
<line x1="10" y1="50" x2="90" y2="50" stroke="black" stroke-width="2" />
<line x1="70" y1="30" x2="90" y2="50" stroke="black" stroke-width="2" />
<line x1="70" y1="70" x2="90" y2="50" stroke="black" stroke-width="2" />
</g>
</svg>
'
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Test the rotation is changed as 'angle' is changed
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arrow_angle <- -30
final_svg <- glue::glue(arrow_text, .open = "{{", .close = "}}")
grid::grid.draw( svg_to_rasterGrob(final_svg) )
```
#### Create a plot with rotating SVG arrow
```{r fig.width = 6, fig.height=4}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create a plausible vector field
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
set.seed(13)
value <- 360 * as.vector(ambient::normalise(ambient::noise_perlin(c(10, 10))))
data <- cbind(expand.grid(x=1:10, y=1:10), value)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Use 'value' to control the arrow angle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ggplot(data) +
geom_raster(aes(x, y, fill = value)) +
geom_point_svg(
aes(x, y, arrow_angle = I(value)),
svg = arrow_text,
size = 10#,
# defaults = list(arrow_angle = 0)
) +
theme_bw() +
theme(legend.position = 'none') +
scale_fill_viridis_c()
```