Author: Claus O. Wilke
Date: 2025-12-05

# Labeled isolines

#### Claus O. Wilke

#### 2025-12-05

Labeled isolines can be drawn in the grid graphics system via the `isolines_grob()` function.

    library(isoband)
    library(grid)

    x <- (0:(ncol(volcano) - 1))/(ncol(volcano) - 1)
    y <- ((nrow(volcano) - 1):0)/(nrow(volcano) - 1)
    lines <- isolines(x, y, volcano, 5*(19:38))

    g <- isolines_grob(
      lines, breaks = 20*(5:10),
      gp = gpar(
        fontsize = 10,
        lwd = c(1, 2, 1, 1),
        col = c("grey50", "grey20", "grey50", "grey50")
      )
    )

    grid.newpage()
    grid.draw(g)

The function places labels at the isolines specified via the `breaks` argument, and it crops isolines around the labels so no lines run into the labels. It is possible to leave extra space around the labels using the `margin` argument.

    g <- isolines_grob(
      lines, breaks = 20*(5:10),
      margin = unit(c(3, 5, 3, 5), "pt"), # margin specified as top, right, bottom, left
      gp = gpar(
        fontsize = 10,
        lwd = c(1, 2, 1, 1),
        col = c("grey50", "grey20", "grey50", "grey50")
      )
    )

    grid.newpage()
    grid.draw(g)

Where the labels are drawn can be controlled via the `label_placer` argument. A few different label placement strategies are provided. The default, `label_placer_minmax()`, places labels at the maximum and minimum y value for each isoline. However, this label placer can be further customized. For example, labels can be placed at maximum and minimum x values and at a fixed rotation angle of 90 degrees.

    g <- isolines_grob(
      lines, breaks = 20*(5:10),
      gp = gpar(
        fontsize = 10,
        lwd = c(1, 2, 1, 1),
        col = c("grey50", "grey20", "grey50", "grey50")
      ),
      label_placer = label_placer_minmax(
        placement = "rl", # place labels right and left, i.e., min and max x
        rot_adjuster = angle_fixed(pi/2) # set fixed angle of 90 degrees
      )
    )

    grid.newpage()
    grid.draw(g)

The label placer `label_placer_none()` doesn’t place any labels.

    g <- isolines_grob(
      lines, breaks = 20*(5:10),
      gp = gpar(
        lwd = c(1, 2, 1, 1),
        col = c("grey50", "grey20", "grey50", "grey50")
      ),
      label_placer = label_placer_none()
    )

    grid.newpage()
    grid.draw(g)

We can also place labels entirely manually by using `label_placer_manual()`. This label placer takes as arguments the breaks that should be labeled and the corresponding coordinates and label angles. Breaks for which no coordinates are specified are ignored. If multiple coordinates are supplied for the same break then multiple labels are placed for that break.

    g <- isolines_grob(
      lines, breaks = 20*(5:10),
      gp = gpar(
        fontsize = 12,
        lwd = c(1, 2, 1, 1),
        col = c("grey50", "grey20", "grey50", "grey50")
      ),
      label_col = "red",
      label_placer = label_placer_manual(
        breaks = c("120", "160", "160"),
        x = c(0.15, 0.5, 0.6),
        y = c(0.19, 0.51, 0.87),
        theta = 0
      )
    )

    grid.newpage()
    grid.draw(g)

Because isolines are cropped around the labels, the labeling strategy works even if the isolines are drawn on top of a colored background. For example, we could draw filled isobands using `isobands_grob()` and then draw labeled lines on top.

    viridis_pal <- colorRampPalette(
      c("#440154", "#414487", "#2A788E", "#22A884", "#7AD151", "#FDE725"),
      space = "Lab"
    )

    bands <- isobands(x, y, volcano, 5*(18:38), 5*(19:39))

    b <- isobands_grob(
      bands,
      gp = gpar(col = NA, fill = viridis_pal(21), alpha = 0.4)
    )
    l <- isolines_grob(
      lines, breaks = 20*(5:10),
      gp = gpar(
        fontsize = 10,
        lwd = c(1, 2, 1, 1),
        col = c("grey50", "grey20", "grey50", "grey50")
      )
    )

    grid.newpage()
    grid.draw(b)
    grid.draw(l)