1

I'm trying to create a custom ggplot2 geom called geom_geoheat, but I'm running into an error when converting the geom to a grob. I am using ggprotos of GeomTile and GeomRect (where tile inherits most of rect's properties). The error message indicates an issue with grid::unit() in grid::rectGrob(), but I can't seem to debug the x and units parts. Here is my function and the error message:

library(ggplot2)
geom_geoheat <- function(
  mapping = NULL, data = NULL,
  border_col = "white", border_size = 2,
  lbl_size = 3, dark_lbl = "black", light_lbl = "white",
  radius = grid::unit(6, "pt"),
  ...,
  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) {

  ggplot2::layer(
    data = data,
    mapping = mapping,
    stat = "identity",
    geom = GeomGeoHeat,
    position = "identity",
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      border_col = border_col,
      border_size = border_size,
      lbl_size = lbl_size,
      dark_lbl = dark_lbl,
      light_lbl = light_lbl,
      radius = radius,
      na.rm = na.rm,
      ...
    )
  )
}

GeomGeoHeat <- ggproto("GeomGeoHeat", GeomTile,
  required_aes = c("fill", "facet_col"),
  default_aes = aes(
    fill = "grey20", colour = NA, size = 0.1, linetype = 1,
    facet_col = "country",
    label = "code",
    angle = 0, hjust = 0.5,
    vjust = 0.5, alpha = NA, family = "", fontface = 1, lineheight = 1.2
  ),
  extra_params = c("na.rm"),
  setup_data = function(data, params) {
    facet_data <- data.frame(data, stringsAsFactors=FALSE)
    facet_col <- facet_col
    merged_data <- mergeGridAndData(facet_data, grid_data, facet_col)
    merged_data$y <- -merged_data$y
    print(summary(merged_data))
    merged_data
  },
  draw_panel = function(self, data, panel_params, coord,
                        border_col = "white", border_size = 2,
                        lbl_size = 3, dark_lbl = "black", light_lbl = "white",
                        radius = grid::unit(6, "pt")) {
    print(head(data))
    coord <- coord_equal()
    grid::gList(
      GeomTile$draw_panel(data, panel_params, coord)
    ) -> grobs
    ggname("geom_geoheat", grid::grobTree(children = grobs))
  },
  draw_key = ggplot2::draw_key_polygon
)

# Merge user data with grid data

mergeGridAndData <- function(facet_data, grid_data, facet_col)
{
  
  print(summary(facet_data))
  
  if (max(nchar(facet_data[,"facet_col"])) <= 3) {
    merge.grid <- "code"
  } else {
    merge.grid <- "name"
  }
 
  # Rename rows and columns to x and y for panel coordinates. Flip row coordinates to start at bottom left.
  colnames(grid_data) <- c("name", "code", "y", "x")
  

  merged_data <- merge(grid_data, facet_data,
                       by.x = merge.grid, by.y = "facet_col", all = FALSE, sort=TRUE) 
  
}

and the error:

Error in `geom_geoheat()`:
! Problem while converting geom to grob.
ℹ Error occurred in the 1st layer.
Caused by error in `unit()`:
! 'x' and 'units' must have length > 0
 —> more specifically, the error occurs in grid::rectGrob(...)
                                                     └─grid::unit(x, default.units)
                                                            └─base::stop("'x' and 'units' must have length > 0")

The desired output would be a CARTOGRAM HEATMAP. I believe the issue is in the draw_panel part of GeomRect (as draw_panel gets inherited into the Tile). However, I've been unsuccessful in debugging the x and units part, primarily because I don’t know how to call units from what seems a deeply entrenched grid function within rectGrob.

Here is minimal code needed to try it out yourselves:

# Example dataset
data <- data.frame(
  country = c("USA", "Canada", "Germany", "Japan"),
  usage = c(50, 30, 45, 60)
)

# Dummy grid_data
grid_data <- data.frame(
  name = c("United States", "Canada", "Germany", "Japan"),
  code = c("US", "CA", "DE", "JP"),
  row = c(1, 2, 3, 4),
  col = c(1, 2, 3, 4)
)

facet_data <- data
facet_col <- "country"

# Example usage
ggplot(data = data,
       mapping = aes(fill = usage, facet_col = country))  +
  geom_geoheat()

I am a relative novice when it comes to asking questions here, so if I left out anything you feel is critical, please let me know and I'd be happy to provide it :) .

Any insights on what might be causing this error and how to resolve it would be greatly appreciated!

3
  • 4
    mergeGridAndData() where do you define this function?
    – M--
    Commented Jul 8 at 18:12
  • @M--, apologies, edit added!
    – nostrum
    Commented Jul 9 at 7:38
  • I'm fairly sure this has everything to do with your use of facets without a custom facet grob. It's failing when it tries to assign facet labels (make_labels). You can read about that here.
    – Kat
    Commented Jul 9 at 19:20

0

Browse other questions tagged or ask your own question.