├── .gitignore
├── README.md
├── images
├── rstudio_01.png
└── rstudio_02.png
├── rstudiopostcard.Rproj
└── source
├── rstudio_01.R
├── rstudio_02.R
└── stepping_stone.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rhistory
2 | .RData
3 | .Rproj.user
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # RStudio postcard
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/images/rstudio_01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djnavarro/rstudiopostcard/6e866a21179c1f64b7d57c44a5140dfd189df1d2/images/rstudio_01.png
--------------------------------------------------------------------------------
/images/rstudio_02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/djnavarro/rstudiopostcard/6e866a21179c1f64b7d57c44a5140dfd189df1d2/images/rstudio_02.png
--------------------------------------------------------------------------------
/rstudiopostcard.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
--------------------------------------------------------------------------------
/source/rstudio_01.R:
--------------------------------------------------------------------------------
1 |
2 | library(Rcpp)
3 | library(tidyverse)
4 | library(ambient)
5 | library(flametree)
6 | library(ggforce)
7 | library(paletteer)
8 | library(here)
9 |
10 | sourceCpp(here("source", "stepping_stone.cpp"))
11 | output <- here("images", "rstudio_01.png")
12 |
13 |
14 | # generate stepping stone background --------------------------------------
15 |
16 | cat("generating image...\n")
17 |
18 | # parameters
19 | seed_ss <- 339
20 | shades <- 1000
21 | grains_wide <- 500
22 | grains_high <- 750
23 |
24 | palette <- paletteer_c(
25 | palette = "ggthemes::Classic Blue",
26 | n = shades
27 | )
28 |
29 | # seed for RNG
30 | set.seed(seed_ss)
31 |
32 | # create long grid for the raster with appropriate aspect ratio
33 | ar <- grains_high / grains_wide
34 | raster <- long_grid(
35 | x = seq(0, 1, length.out = grains_wide),
36 | y = seq(0, ar, length.out = grains_high)
37 | )
38 |
39 | # initialise raster using worley noise
40 | raster$base <- fracture(
41 | noise = gen_worley,
42 | fractal = fbm,
43 | octaves = 5,
44 | frequency = 3,
45 | value = "distance2",
46 | seed = seed_ss,
47 | x = raster$x,
48 | y = raster$y
49 | )
50 |
51 | # convert base raster image to integer index
52 | raster$base <- as.integer(ceiling(normalise(raster$base) * shades))
53 |
54 | # convert to matrix and run stepping stone automaton
55 | ss <- matrix(raster$base, grains_wide, grains_high)
56 | ss <- t(timestep(ss, 200))
57 |
58 | # read colours off the ss matrix
59 | raster$shade <- palette[ss]
60 |
61 |
62 |
63 |
64 |
65 | # generate flametree ------------------------------------------------------
66 |
67 | seed_ft <- 1
68 | set.seed(seed_ft)
69 |
70 | # create the tree
71 | ftree <- flametree_grow(
72 | time = 12,
73 | seed = seed_ft,
74 | angle = c(-2:4) * 10,
75 | scale = c(.6, .8, .9)
76 | )
77 |
78 | # compute aspect ratio of generated tree
79 | ar2 <- with(ftree, (max(coord_y) - min(coord_y))/(max(coord_x) - min(coord_x)))
80 |
81 | # scale the tree image to fit the postcard
82 | ftree <- ftree %>%
83 | mutate(
84 | coord_x = normalise(coord_x, to = range(raster$x)),
85 | coord_y = normalise(coord_y, to = range(raster$y))
86 | ) %>%
87 | mutate(
88 | coord_x = coord_x * min(1, ar/ar2),
89 | coord_y = coord_y * min(1, ar2/ar)
90 | ) %>%
91 | mutate(
92 | coord_x = .045 + coord_x * .9,
93 | coord_y = coord_y * .9
94 | )
95 |
96 |
97 | # "leaf" coordinates are at terminal locations (id_step = 2)
98 | # on the terminal branches (id_leaf == TRUE) in the tree
99 | vleaf <- ftree %>%
100 | filter(id_leaf == TRUE, id_step == 2)
101 |
102 |
103 |
104 |
105 | # generate raindrops ------------------------------------------------------
106 |
107 | seed_rd <- 1
108 | set.seed(seed_rd)
109 |
110 | # rain
111 | rain <- expand_grid(
112 | x = seq(.01, .99, length.out = 50),
113 | y = seq(.01 * ar, .99 * ar, length.out = round(50 * ar))
114 | ) %>%
115 | mutate(droplet = runif(n()) < .1) %>%
116 | group_by(x) %>%
117 | mutate(droplet = droplet | lag(droplet, default = FALSE) | lag(droplet, 2, default = FALSE)) %>%
118 | ungroup()
119 |
120 | rain1 <- rain %>%
121 | filter(droplet == TRUE)
122 |
123 | rain2 <- rain %>%
124 | group_by(x) %>%
125 | filter(droplet, !lag(droplet) | y == min(y)) %>%
126 | ungroup()
127 |
128 |
129 |
130 | # render the image --------------------------------------------------------
131 |
132 | cat("rendering image...\n")
133 |
134 | pic <- ggplot(
135 | data = raster,
136 | mapping = aes(x, y, fill = shade)
137 | ) +
138 |
139 | # background is the raster object
140 | geom_raster() +
141 |
142 | # underlay the rain sparkle
143 | geom_point(
144 | data = rain2,
145 | mapping = aes(x, y),
146 | size = 1,
147 | alpha = 1,
148 | color = "white",
149 | show.legend = FALSE,
150 | inherit.aes = FALSE
151 | ) +
152 |
153 | # add the rain drops
154 | geom_point(
155 | data = rain1,
156 | mapping = aes(x, y),
157 | size = .5,
158 | alpha = 1,
159 | color = "black",
160 | show.legend = FALSE,
161 | inherit.aes = FALSE
162 | ) +
163 |
164 | # tree trunk is drawn using geom_bezier from ggforce
165 | geom_bezier(
166 | data = ftree,
167 | mapping = aes(
168 | x = coord_x,
169 | y = coord_y,
170 | group = id_path,
171 | size = .3 + seg_wid * 3
172 | ),
173 | lineend = "round",
174 | show.legend = FALSE,
175 | inherit.aes = FALSE
176 | ) +
177 |
178 | # overlay the leaves
179 | geom_point(
180 | data = vleaf,
181 | mapping = aes(
182 | x = coord_x,
183 | y = coord_y
184 | ),
185 | size = 1,
186 | color = "white",
187 | show.legend = FALSE,
188 | inherit.aes = FALSE
189 | ) +
190 |
191 | # plot settings
192 | scale_fill_identity() +
193 | scale_size_identity() +
194 | coord_equal() +
195 | scale_x_continuous(expand = c(0, 0)) +
196 | scale_y_continuous(expand = c(0, 0)) +
197 | theme_void() +
198 | NULL
199 |
200 | # export image
201 | ggsave(
202 | filename = output,
203 | plot = pic,
204 | width = grains_wide / 150,
205 | height = grains_high / 150,
206 | dpi = 2400
207 | )
208 |
209 |
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/source/rstudio_02.R:
--------------------------------------------------------------------------------
1 |
2 | library(Rcpp)
3 | library(tidyverse)
4 | library(ambient)
5 | library(flametree)
6 | library(voronoise)
7 | library(paletteer)
8 | library(here)
9 |
10 | sourceCpp(here("source", "stepping_stone.cpp"))
11 | output <- here("images", "rstudio_02.png")
12 |
13 |
14 | # generate stepping stone background --------------------------------------
15 |
16 | cat("generating image...\n")
17 |
18 | # parameters
19 | seed_ss <- 340
20 | shades <- 1000
21 | grains_wide <- 500
22 | grains_high <- 750
23 |
24 | palette <- paletteer_c(
25 | palette = "viridis::magma",
26 | n = shades
27 | )
28 |
29 | # seed for RNG
30 | set.seed(seed_ss)
31 |
32 | # create long grid for the raster with appropriate aspect ratio
33 | ar <- grains_high / grains_wide
34 | raster <- long_grid(
35 | x = seq(0, 1, length.out = grains_wide),
36 | y = seq(0, ar, length.out = grains_high)
37 | )
38 |
39 | # initialise raster using worley noise
40 | raster$base <- fracture(
41 | noise = gen_worley,
42 | fractal = fbm,
43 | octaves = 5,
44 | frequency = 3,
45 | value = "distance2",
46 | seed = seed_ss,
47 | x = raster$x,
48 | y = raster$y
49 | )
50 |
51 | # convert base raster image to integer index
52 | raster$base <- as.integer(ceiling(normalise(raster$base) * shades))
53 |
54 | # convert to matrix and run stepping stone automaton
55 | ss <- matrix(raster$base, grains_wide, grains_high)
56 | ss <- t(timestep(ss, 200))
57 |
58 | # read colours off the ss matrix
59 | raster$shade <- palette[ss]
60 |
61 |
62 |
63 | # generate flametree ------------------------------------------------------
64 |
65 | seed_ft <- 1
66 | set.seed(seed_ft)
67 |
68 | # the "flametree" itself
69 | ftree <- flametree_grow(
70 | time = 10,
71 | seed = seed_ft,
72 | angle = c(-2:4) * 10,
73 | scale = c(.6, .8, .9)
74 | )
75 |
76 | # compute aspect ratio of generated tree
77 | ar2 <- with(ftree, (max(coord_y) - min(coord_y))/(max(coord_x) - min(coord_x)))
78 |
79 | # scale the tree image to fit the postcard
80 | ftree <- ftree %>%
81 | mutate(
82 | coord_x = normalise(coord_x, to = range(raster$x)),
83 | coord_y = normalise(coord_y, to = range(raster$y))
84 | ) %>%
85 | mutate(
86 | coord_x = coord_x * min(1, ar/ar2),
87 | coord_y = coord_y * min(1, ar2/ar)
88 | ) %>%
89 | mutate(
90 | coord_x = .075 + coord_x * .85,
91 | coord_y = coord_y * 1.05
92 | )
93 |
94 | # "leaf" coordinates are at terminal locations (id_step = 2)
95 | # on the terminal branches (id_leaf == TRUE) in the tree
96 | vleaf <- ftree %>%
97 | filter(id_leaf == TRUE, id_step == 2) %>%
98 | sample_frac(.7)
99 |
100 |
101 | # render the image --------------------------------------------------------
102 |
103 | cat("rendering image...\n")
104 |
105 | pic <- ggplot(
106 | data = raster,
107 | mapping = aes(x, y, fill = shade)
108 | ) +
109 |
110 | # the raster object forms the background
111 | geom_raster() +
112 |
113 | # tree trunk is drawn using geom_bezier from the
114 | # ggforce package (loaded by voronoise)
115 | geom_bezier(
116 | data = ftree,
117 | mapping = aes(
118 | x = coord_x,
119 | y = coord_y,
120 | group = id_path,
121 | size = .2 + seg_wid * 3
122 | ),
123 | lineend = "round",
124 | colour = "white",
125 | alpha = .5,
126 | show.legend = FALSE,
127 | inherit.aes = FALSE
128 | ) +
129 |
130 | # leaves generated using the voronoise package (in this instance
131 | # it's more or less identical to geom_voronoi_tile)
132 | geom_voronoise(
133 | data = vleaf,
134 | mapping = aes(
135 | x = coord_x,
136 | y = coord_y
137 | ),
138 | expand = -.0005,
139 | radius = 0,
140 | max.radius = .02,
141 | size = 2,
142 | alpha = 1,
143 | fill = "white",
144 | show.legend = FALSE,
145 | inherit.aes = FALSE
146 | ) +
147 |
148 | # add the marginal distributions
149 | geom_rug(
150 | data = vleaf,
151 | mapping = aes(
152 | x = coord_x,
153 | y = coord_y
154 | ),
155 | length = unit(3, "mm"),
156 | sides = "bl",
157 | size = .1,
158 | alpha = .4,
159 | color = "white",
160 | show.legend = FALSE,
161 | inherit.aes = FALSE
162 | ) +
163 |
164 | # bunch of settings...
165 | scale_fill_identity() +
166 | scale_size_identity() +
167 | coord_equal() +
168 | scale_x_continuous(expand = c(0, 0)) +
169 | scale_y_continuous(expand = c(0, 0)) +
170 | theme_void() +
171 | NULL
172 |
173 | # export image
174 | ggsave(
175 | filename = output,
176 | plot = pic,
177 | width = grains_wide / 150,
178 | height = grains_high / 150,
179 | dpi = 2400
180 | )
181 |
--------------------------------------------------------------------------------
/source/stepping_stone.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | using namespace Rcpp;
3 |
4 | // [[Rcpp::export]]
5 | IntegerMatrix timestep(IntegerMatrix x, int iter) {
6 |
7 | // size of the matrix
8 | int nrow = x.nrow();
9 | int ncol = x.ncol();
10 |
11 | // indexing and weighting variables
12 | double wt;
13 | int rind;
14 | int cind;
15 | int rstp;
16 | int cstp;
17 |
18 | for(int i = 0; i < iter; i++) {
19 | for(int r = 0; r < nrow; r++) {
20 | for(int c = 0; c < ncol; c++) {
21 |
22 | // sample from binomial distributions
23 | rstp = R::rbinom(4, 0.5);
24 | cstp = R::rbinom(4, 0.5);
25 |
26 | // find corresponding indices
27 | rind = r + rstp - 2;
28 | cind = c + cstp - 2;
29 |
30 | // truncate at the boundaries
31 | if(rind < 0) {rind = 0;}
32 | if(cind < 0) {cind = 0;}
33 | if(rind >= nrow) {rind = nrow - 1;}
34 | if(cind >= ncol) {cind = ncol - 1;}
35 |
36 | // replace
37 | x(r,c) = x(rind, cind);
38 | }
39 | }
40 | }
41 |
42 | return x;
43 | }
--------------------------------------------------------------------------------