Reputation: 4273
If I want to save some square grid in R, that's easily done.
Say,
| | 0 | 1 | 2 |
|----|------|-------|-------|
| 0 | TRUE | TRUE | FALSE |
| 1 | NA | FALSE | TRUE |
| 2 | TRUE | TRUE | FALSE |
is stored as cartesian coordinate system
m <- matrix(data = c(TRUE, TRUE, FALSE, NA, FALSE, TRUE, TRUE, TRUE, FALSE), nrow = 3, ncol = 3, byrow = FALSE)
and existing methods and math work as expected:
apply(X = m, MARGIN = 2, FUN = "sum")
# [1] 2 NA 2
print(m)
# [,1] [,2] [,3]
#[1,] TRUE NA TRUE
#[2,] TRUE FALSE TRUE
#[3,] FALSE TRUE FALSE
(I know I can also reshape2::melt
this into long form, but I like it wide, because that's what the UI looks like).
So far so good, familiar, intuitive.
Now enter the hexagonal grid.
I understand from Amit Patel's marvellous/authoritative introduction to hex grids that I really ought to save such a grid using a cube coordinate system, as in the above example, because otherwise (= with 2d cartesian coordinates plus offsets) linear algebra operations don't work anymore, and general code grossness ensues. I get that (I think).
(For more details, again, see Amit Patel's fantastic explainer).
Entering this data in wide form via array()
seems completely bonkers, because many cells don't even exist (and NA
is already used).
So I enter/store this in long form, like so:
df <- rbind(c(1, 0, -1, FALSE),
c(0, 1, -1, NA),
c(1, -1, 0, TRUE),
c(0, 0, 0, TRUE),
c(-1, 1, 0, FALSE),
c(0, -1, 1, NA),
c(-1, 0, 1, TRUE))
colnames(df) <- c("y", "x", "z", "value")
df
# y x z value
#[1,] 1 0 -1 0
#[2,] 0 1 -1 NA
#[3,] 1 -1 0 1
#[4,] 0 0 0 1
#[5,] -1 1 0 0
#[6,] 0 -1 1 NA
#[7,] -1 0 1 1
This dataframe has all the data, but doesn't "know" in any way, that x
, y
and z
are diagonal coordinates.
How can I:
colSums()
, or apply()
)print
to something like this:(SE won't even properly highlight this printed hex grid, hence the screenshot.)
What, in short, would be the elegant / recommended / canonical way to "natively" store such a hexagonal grid in R?
I am vaguely aware that I could probably implement my own S3 OO for this, though I was hoping that this might already exist in some form or another. I did find lots of packages that do hex binning on continuous data, but they didn't seem to deal with storing hex grids, or at least didn't expose those internals.
Upvotes: 3
Views: 714
Reputation: 128
1. store this in a wide form where I can easily use linear and matrix algebra
Probably, the axial coordinates mentioned in http://www.redblobgames.com/grids/hexagons/#coordinates are the best choice here. This could give the option to convert to a standard ij-matrix with i=x and j=y, you just have to specify what to put into the matrix-cells which are not covered by your hex-grid (your own "NA"). Then you can operate along the dimension x and y as usual and have a matrix with just empty triangular upper right and lower left triangles. (This is not bonkers, but the natural way. At best you have to find a different solution for your NA in the your data. Sorry for not fiddling out the code for your example.)
2. use established methods (say, colSums(), or apply())
Using the dplyr package you can
df %>% as_data_frame() %>% group_by(x) %>% summarize(sum(value))
to sum for fixed x or the like.
3. as well as conveniently print
I don't have a solution for print, but displaying labels with ggplot2 can be a solution
df %>% as_data_frame() %>% ggplot(aes(x=x+0.5*y, y=y, label=value)) + geom_text()
Notes: The result provided here is a flipped version of what you wanted to have printed, but I hope you can find the right flip yourself. x=x+0.5*y
serves here to give you the hex shape you are aiming at. With x=x
you just have a skew hexagon.
What, in short, would be the elegant / recommended / canonical way to "natively" store such a hexagonal grid in R?
You found it already. For computation you use your df. For storage it is a bit more efficient to use the axial one. You can extract the z coordinate back easily.
Upvotes: 3