---
title: "Simple Solar Eclipse in R"
author: "Esther Weidauer"
output:
html_document:
toc: true
highlight: zenburn
number_sections: true
df_print: default
---
```{r prep work, include = FALSE}
library(tidyverse)
```
You can download the RMarkdown source code for this page here.
## Rendering a simple solar eclipse
Generate 200.000 points on a circle with normal-distributed angle (`al`), so that a few more are on one side of the circle, and a normal-distributed positive offset from the radius (`dr`) to spread them out a bit.
```{r}
n <- 200000
tibble(
dr = rnorm(n = n, sd=0.04, mean = 0) %>% abs,
al = rnorm(n = n, sd = 1.0, mean = 0)
) %>% mutate(
r = 1 + dr,
x = r * cos(al),
y = r * sin(al)
) -> points
```
Set up a custom ggplot theme with no axes and a black background.
```{r}
theme_void() %+replace% theme(
legend.position="none",
panel.background = element_rect(fill="black")
) -> th
```
Then render as a scatter plot in white on a black background with low opacity.
```{r}
#| fig.width = 6,
#| fig.height = 4
points %>% ggplot(aes(x=x, y=y)) +
geom_point(alpha = 0.2, shape = ".", color = "white") +
coord_equal() +
xlim(-3, 3) +
ylim(-2, 2) +
th
```
## Adding a better corona effect
Make two subsets of the points: `p1` with $n = 40.000$ and `p2` with $n = 20000$
`p1` will remain unchanged and be rendered just as before. `p2` will be used for drawing outward pointing rays to give that typical look of the sun's corona during an eclipse.
Add an identifier to each point in `p2`, like the row number. It doesn't really matter what it is as long as it's unique to each point. We need that to control which points will be connected into lines when rendering.
Also add new value $c = 100$ to them. We'll need that later.
```{r}
points %>% slice_sample(n = 40000) -> p1
points %>% slice_sample(n = 20000) -> p2
p2 %>% mutate(
id = row_number(),
c = 100,
d = abs(rnorm(nrow(p2), mean = 0, sd = 0.07))
) -> p2
```
Move the points from `p2` all further outward in a loop. Recalculate their X and Y coordinates as well and decrease $c$ on each loop. Then merge the moved copies and originals (`p2`) together with `bind_rows()` into a new tibble (`rays`).
```{r}
rays <- p2
steps <- 10
for (i in 1:steps) {
p2 %>% mutate(
r = r + d,
x = r * cos(al),
y = r * sin(al),
c = c - (100 / steps)
) -> p2
p2 %>% bind_rows(rays) -> rays
}
```
Plot them again, but this time add a line graph (`geom_path`) between each set of points that have the same identifier $i$ and set the opacity (`alpha`) to the value of $c$.
Set the opacity of the `p1` points to a value much higher than 100. We want them to be brighter than the rays. We also need to control how the opacity (`alpha`) is handled for this with `scale_alpha_continuous`.
*This might take a little while to run …*
```{r message=FALSE}
#| fig.width = 8,
#| fig.height = 8
ggplot() +
geom_path(data = rays,
aes(x = x, y = y, group = id, alpha = c),
color ="white", linewidth = 2) +
geom_point(data = p1,
aes(x = x, y = y, alpha = 800),
shape = ".",
color = "white") +
coord_equal() +
xlim(-4, 4) +
ylim(-4, 4) +
scale_alpha_continuous(range = c(0, 0.2)) +
th
```