Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

geom_tile() not square when saving high res map (may be a more fundamental R graphics issue) #6029

Open
jack-davison opened this issue Aug 5, 2024 · 3 comments

Comments

@jack-davison
Copy link

A colleague is encountering an issue saving a large geographical heatmap made using geom_tile(); when saving this quite large, high-res plot as a PNG image the squares produced by geom_tile() aren't square!

reprex:

set.seed(123)
 
testdf <-
expand.grid(
  x = seq(500, 655500, 1000),
  y = seq(500, 655500, 1000)
) 
testdf |>
  dplyr::mutate(col = sample(letters[1:4], replace = TRUE, nrow(testdf))) |>
  ggplot(aes(x, y, fill = col)) +
  geom_tile()
 
ggsave("testrprex.png", dpi = 300, width = 15, height = 15)

This produces the below - annotations mine:

image

We believe this is to do with how R/ggplot2 interpolates between rectangles as when antialiasing is turned off (snap_rect = FALSE) the grid is a lot more regular, but has a sort of grid artefact where you can see horizontal/vertical lines - almost like a mosaic.

image

Is there a fix to avoid these non-square tiles when saving without getting the gridlines? As it is a spatial heatmap, it's important for the client to be able to zoom in quite close to each square, and they may question why some are rectangular!

Thanks very much

@jack-davison jack-davison changed the title geom_tile() not square when saving (may be a more fundamental R graphics issue) geom_tile() not square when saving his res map (may be a more fundamental R graphics issue) Aug 5, 2024
@jack-davison jack-davison changed the title geom_tile() not square when saving his res map (may be a more fundamental R graphics issue) geom_tile() not square when saving high res map (may be a more fundamental R graphics issue) Aug 5, 2024
@teunbrand
Copy link
Collaborator

To quickly clarify one point; geom_tile() is only expected to deliver square rectangles when the aspect ratio is fixed.

On to the main thing; I think the issue you're indicating is that the tiles have different pixel widths and columns look irregular. I've opened the figure in MS Paint, and some columns are 5 pixels wide, whereas others are 6 pixels wide.

ggplot2 doesn't really concert itself with how pixels are rendered in raster images. To get pixel-perfect tiles, you probably would have to manually calculate the size of the panels to an exact multiple of your number of tiles. I don't really have experience with this so I wouldn't be able to tell you the calculation on top of my head.

@jack-davison
Copy link
Author

Hi Teun,

To quickly clarify one point; geom_tile() is only expected to deliver square rectangles when the aspect ratio is fixed.

Yes, sorry, should have included that! The tiles are indeed a fixed aspect ratio - the "real world" data effectively follows the same pattern/limits the reprex - seq(500, 655500, 1000).

ggplot2 doesn't really concert itself with how pixels are rendered in raster images. To get pixel-perfect tiles, you probably would have to manually calculate the size of the panels to an exact multiple of your number of tiles. I don't really have experience with this so I wouldn't be able to tell you the calculation on top of my head.

Understood, thanks very much - I didn't think it was a {ggplot2} issue specifically so good to verify. We can see if we can do the maths wrt to the size of the panels to see if we can force them to be square.

@teunbrand
Copy link
Collaborator

Using grid units in this helper will allow you to set the panel size in grid units, but I'm not 100% on top of how to translate grid units to pixels.

So if you have a 1000 tiles, each of 5 pixels let's say, you need 5000 pixels.
By default, scale expansion adds 10% so that is 5500 pixels.
At 300 dpi that should be 5500 / 300 ~= 18.33 inches.
However, when we set the panel size that way, the exported figure has a mix of 7 or 8 pixels per tile, not 5.
It appears thus that I've overlooked something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants