Many plotting functions in R use the graphical parameter pch
to specify the shape of the data points. According to R documentation, there are 26 vector shapes to pick between, as well as the option to use ASCII characters.
Would it be possible to specify other simple vector shapes to use in plots, such as the examples below?
There are some answers on stack overflow for creating plots with images as the points, but I feel this is a distinct question, as I would like to create vector shapes compatible with other graphical parameters such as col
and cex
. Another answer suggests using unicode symbols which is my best option so far, but it's still difficult to find the precise symbols I want.
Surely R has somewhere stored the code that creates the 26 vector shapes that are available, and it would be possible to write code in the same format for new shapes that could be used in the same way? A pointer in the right direction (or confirmation that this is totally impossible) would be great.
You can write a function that draws arbitrary shapes as a scatter plot. It functions in the same way as the base R graphics function points
, except it can take a custom shape as an argument:
points_custom <- function(x, y, shape, col = 'black', cex = 1, ...) {
if(missing(shape)) {
points(x, y, col = col, cex = cex, ...)
}
else {
shape <- lapply(shape, function(z) z * cex)
Map(function(x_i, y_i) {
a <- grconvertX(grconvertX(x_i, 'user', 'inches') + shape$x, 'inches', 'user')
b <- grconvertY(grconvertY(y_i, 'user', 'inches') + shape$y, 'inches', 'user')
polygon(a, b, col = col, border = col, ...)
}, x_i = x, y_i = y)
}
invisible(NULL)
}
If we create some test data, we will see that the default behaviour is the same as points
:
set.seed(1)
x_vals <- 1:10
y_vals <- sample(10)
plot(1:10, , type = 'n')
points_custom(x_vals, y_vals)
The difference is that we can pass arbitrary shapes to be used to draw the points. These shapes should take the form of an x, y list of co-ordinates of the vertices of your shape. These will be used to draw polygons. For example, your 'propeller' shape on the left would be approximated by the following co-ordinates:
my_shape1 <- list(x = c(-0.01, 0.01, 0.01, 0.0916, 0.0816,
0, -0.0816, -0.0916, -0.01),
y = c(0.1, 0.1, 0.01, -0.0413, -0.0587,
-0.01, -0.0587, -0.0413, 0.01))
And your 'angled Z' shape on the right by these co-ordinates:
my_shape2 <- list(x = c(0.007, 0.007, 0.064, 0.078, -0.007,
-0.007, -0.064, -0.078),
y = c(0.078, -0.042, 0.007, -0.007, -0.078,
0.042, -0.007, 0.007))
These shapes can be passed to the points_custom
function like so:
plot(1:10, , type = 'n')
points_custom(x_vals, y_vals, my_shape1)
plot(1:10, , type = 'n')
points_custom(x_vals, y_vals, my_shape2)
And we can apply the usual cex
and col
arguments:
plot(1:10, , type = 'n')
points_custom(x_vals, y_vals, my_shape1, col = 'red', cex = 2)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With