Created
June 10, 2022 01:02
-
-
Save aaronschiff/ed9334cdeae2bf43b7e5d70d1d17c42f to your computer and use it in GitHub Desktop.
Create geom_tile chart with tiles of fixed size
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The objective is to make a faceted ggplot 'heatmap' with geom_tile where the | |
# rendered tiles in the output PNG file have a fixed width and height, | |
# regardless of whatever else is in the chart. | |
# When ggplot charts are built, the height and width of all components are | |
# predetermined *except* for the facet panels. Thus the approach here is to | |
# render an initial version of the chart to determine the height and width | |
# of the predetermined elements. Then the overall height and width of the | |
# output PNG are calculated based on what is needed to give the rendered | |
# tiles the desired size. | |
library(tidyverse) | |
library(grid) | |
# Target tile size | |
target_tile_width <- 1.0 | |
target_tile_height <- 0.5 | |
target_tile_unit <- "cm" | |
# Test chart data | |
dat <- tibble( | |
y = c("A", "A", "A", "B", "B", "B", "C", "C", "C", "D", "D", "D", "E", "E", "E"), | |
x = rep(c(1L, 2L, 3L), 5), | |
outcome = c("high", "high", "low", "high", "high", "low", "low", "high", "low", "low", "low", "low", "high", "high", "low"), | |
area = c(rep("Lower", 9), rep("Upper", 6)) | |
) | |
# Create chart | |
chart <- dat |> | |
ggplot(mapping = aes(y = y, x = x, fill = outcome)) + | |
geom_tile(colour = "white", size = 1) + | |
facet_grid(rows = vars(area), scales = "free", space = "free") + | |
theme_minimal() + | |
labs( | |
title = "Test grid", | |
x = "X axis", | |
y = "Y axis" | |
) | |
# Number of rows and colums of tiles in the chart | |
# Probably could calculate this from chart? | |
n_tile_rows <- 5L | |
n_tile_cols <- 3L | |
# Clear any existing viewports | |
popViewport(n = 0L) | |
# Make a temporary viewport to do our size calculations in | |
# I don't think the size of this matters but it needs to be in the | |
# same units as target_tile_unit | |
temp_vp <- viewport( | |
width = unit(x = 2 * n_tile_cols * target_tile_width, units = target_tile_unit), | |
height = unit(x = 2 * n_tile_rows * target_tile_height, units = target_tile_unit), | |
xscale = c(0, 1), | |
yscale = c(0, 1) | |
) | |
pushViewport(temp_vp) | |
# Build the chart | |
g <- ggplot_gtable(ggplot_build(chart)) | |
# Calculate known widths and heights of fixed elements | |
# Panel elements will have 'null' units and will be excluded from these sums | |
known_wds <- sum(convertWidth(x = g$widths, unitTo = target_tile_unit, valueOnly = TRUE)) | |
known_hts <- sum(convertHeight(x = g$heights, unitTo = target_tile_unit, valueOnly = TRUE)) | |
# Calculate the required output width and height | |
output_width <- known_wds + n_tile_cols * target_tile_width | |
output_height <- known_hts + n_tile_rows * target_tile_height | |
# Save chart | |
ggsave( | |
plot = chart, | |
filename = "test.png", | |
device = "png", | |
width = output_width, | |
height = output_height, | |
units = target_tile_unit, | |
bg = "white" | |
) | |
# Clean up temporary viewport | |
popViewport() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment