If you are tired of the point
types available in R base graphics and want to break your report
routine, you can use the package snowflakes
. The package
contains one function that plots random snowflakes that can be used
instead of points. The snowflakes have some useful properties. Just like
points in R base graphics, the snowflakes are round, no matter what
aspect ratio you are using. Another nice property is that the snowflakes
are scaleable: if you increase the size of the snowflake, its crystal
width will increase accordingly. Most importantly, there is an infinite
number of snowflake patterns that you can choose from. Each pattern is
uniquely determined by a random seed. Snowflakes can be plotted using
different sizes, widths, angles, and of course, colors. The following
examples demonstrate how to create all kinds of realistic looking
snowflakes.
First, let’s create a simple plot. Suppose we need to plot a quadratic function, Y = (X − 1)2. Instead of points, we use snowflakes plotted in a transparent gray color. Transparent colors make snowflakes look more like crystals.
xCoor = seq(0, 2, .25)
yCoor = (xCoor-1)^2
radius = 0.1
set.seed(1)
par(mar = c(0, 0, 0, 0))
plot(xCoor, yCoor, type="l", axes = FALSE, ylab="", xlab="", ylim = range(yCoor) + radius*c(-1, 1)*0.7, xlim = range(xCoor) + radius*c(-1, 1)*0.7, col=gray(.9))
snowflakes(xCoor = xCoor, yCoor = yCoor, radius = radius, color = "#22222222")
## [1] 68 39 1 34 43 14 82 59 51
Quadratic function plotted using snowflakes (in transparent gray) instead of points.
Note that in the above plot, every snowflake is unique. The pattern of each snowflake is defined by a random seed. The function also returns the seeds it used for generating the snowflakes in case you want to reproduce them later.
The next example demonstrates the use of argument
deltaCoef
. It defines the width of the snowflake’s
crystal
.
xCoor = seq(0, 1, .25)
yCoor = xCoor
radius = 0.15
set.seed(1)
par(mar = c(0, 0, 0, 0))
plot(xCoor, yCoor, type="l", axes = FALSE, ylab="", xlab="",
ylim = range(yCoor) + radius*c(-1, 1)*0.7,
xlim = range(xCoor) + radius*c(-1, 1)*0.7, col=gray(.9))
returnedSeeds = snowflakes(xCoor = xCoor, yCoor = yCoor, radius = radius, seeds = c(9492), deltaCoef = 15 - (0:(length(xCoor)-1))*3, color = "#22222222")
Same snowflake pattern, but different crystal widths.
Here is another example. In the plot below, we only use three
snowflake patterns with seeds 1
, 2
, and
3
. We also vary the orientation and the color of the
snowflakes. In order to define the colors we use arguments
color
and anotherColor
. Argument
color
changes and argument anotherColor
stays
the same in order to create an interesting effect. Also in this example,
we modified the aspect ratio argument of function plot
, but
the snowflakes are still round. Note that each snowflake is facing the
center of the spiral because of the way we chose argument
orientation
. You can see, however, that the orientation is
not exact. This happens because of the way the aspect ratio correction
of the snowflakes was implemented. In order for orientation to be exact
the aspect ratio of the plot should be 1:1
.
t = seq(0, 5*pi, .5)
xCoor = t*cos(t)
yCoor = t*sin(t)
radius = seq(.6, 1.8, 1.2/(length(t)-1))
orientation = -(pi + t)
set.seed(1)
par(mar = c(0, 0, 0, 0))
plot(xCoor, yCoor, type="l", axes = FALSE, ylab="", xlab="",
ylim = range(yCoor) + max(radius)*c(-1, 1)*0.5,
xlim = range(xCoor) + max(radius)*c(-1, 1)*0.5, col=gray(.9), asp = 2/3)
segments(x0 = rep(0, length(xCoor)), y0 = rep(0, length(xCoor)), x1 = xCoor, y1 = yCoor, col = gray((1:length(xCoor))/(length(xCoor)+1)), lty = 3)
returnedSeeds = snowflakes(xCoor = xCoor, yCoor = yCoor, radius = radius, orientation = orientation, seeds = 1:3, color = gray((1:length(xCoor))/(length(xCoor)+1)), anotherColor = "gray")
Snowflake spiral with each snowflake oriented toward the center of the spiral (well, almost).
Note that in the example above, we used opaque gray colors. If we used transparent colors instead, the snowflakes would look more interesting, which is demonstrated by the next example.
Here, we take the snowflake generator to a higher artistic level :). We first write a function that plots snowflakes using layers of transparent colors.
fancySnowflakes = function(xCoor, yCoor, radius, seeds, orientation = pi/6){
colorCoord = as.hexmode(col2rgb("blue"))
transpBlue =paste("#", paste(colorCoord, collapse=""), "44", sep="")
colorCoord = as.hexmode(col2rgb("white"))
transpWhite =paste("#", paste(colorCoord, collapse=""), "66", sep="")
for (i in 1:length(xCoor)){
snowflakes(xCoor = xCoor[i], yCoor = yCoor[i], radius = radius, color = transpBlue, anotherColor = "#33333333", seeds = seeds[i])
snowflakes(xCoor = xCoor[i], yCoor = yCoor[i], radius = radius, color = transpWhite, anotherColor = transpWhite, seeds = seeds[i])
}
}
Now let’s plot some cool snowflakes. We also print each snowflake’s seed.
numSnowflPerRow = 5
set.seed(2018)
selectSeeds = sample(1:100000, numSnowflPerRow^2)
xCoor = rep(1:numSnowflPerRow, numSnowflPerRow)
yCoor = rep(1:numSnowflPerRow, each = numSnowflPerRow)
radius = .4
par(mar = c(0, 0, 0, 0))
plot(range(xCoor)+c(-1, 1)*.5, range(yCoor)+c(-1, 1)*.5, type="n", axes = FALSE, ylab="", xlab="")
selectSeeds = c(90068, 46258, 41165, 66142, 4636, 37906, 17295, 9250, 30595, 74555, 12669, 62970, 96997, 43447, 81975, 23841, 73197, 8419, 14318, 83885, 29343, 47445, 66721, 29854, 77912)
fancySnowflakes(xCoor = xCoor, yCoor = yCoor, radius = radius, seeds = selectSeeds)
text(xCoor, yCoor, selectSeeds, cex=.5, pos = 3)
Cool looking snowflakes.
There are many other ways to play with snowflakes. For example, they can be generated using a transparent white color and displayed on a dark background. They can also be saved in an svg format and used as static or animated images, see the front page of my website (which is still under construction) as an example.